diff --git a/.core_files.yaml b/.core_files.yaml index 27d51a0ced3..2a6db0a2943 100644 --- a/.core_files.yaml +++ b/.core_files.yaml @@ -91,6 +91,7 @@ components: &components - homeassistant/components/input_number/** - homeassistant/components/input_select/** - homeassistant/components/input_text/** + - homeassistant/components/labs/** - homeassistant/components/logbook/** - homeassistant/components/logger/** - homeassistant/components/lovelace/** diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 839cb00f3de..112b3f27d9c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -40,7 +40,8 @@ "python.terminal.activateEnvInCurrentTerminal": true, "python.testing.pytestArgs": ["--no-cov"], "pylint.importStrategy": "fromEnvironment", - "python.analysis.typeCheckingMode": "basic", + // Pyright type checking is not compatible with mypy which Home Assistant uses for type checking + "python.analysis.typeCheckingMode": "off", "editor.formatOnPaste": false, "editor.formatOnSave": true, "editor.formatOnType": true, diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 03174c0d2b1..51e4526104b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -847,8 +847,8 @@ rules: ## Development Commands ### Code Quality & Linting -- **Run all linters on all files**: `pre-commit run --all-files` -- **Run linters on staged files only**: `pre-commit run` +- **Run all linters on all files**: `prek run --all-files` +- **Run linters on staged files only**: `prek run` - **PyLint on everything** (slow): `pylint homeassistant` - **PyLint on specific folder**: `pylint homeassistant/components/my_integration` - **MyPy type checking (whole project)**: `mypy homeassistant/` @@ -1024,18 +1024,6 @@ class MyCoordinator(DataUpdateCoordinator[MyData]): ) ``` -### Entity Performance Optimization -```python -# Use __slots__ for memory efficiency -class MySensor(SensorEntity): - __slots__ = ("_attr_native_value", "_attr_available") - - @property - def should_poll(self) -> bool: - """Disable polling when using coordinator.""" - return False # ✅ Let coordinator handle updates -``` - ## Testing Patterns ### Testing Best Practices @@ -1181,4 +1169,4 @@ python -m script.hassfest --integration-path homeassistant/components/my_integra pytest ./tests/components/my_integration \ --cov=homeassistant.components.my_integration \ --cov-report term-missing -``` \ No newline at end of file +``` diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1d513ba59e4..703ffd14f38 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -59,7 +59,6 @@ env: # 15 is the latest version # - 15.2 is the latest (as of 9 Feb 2023) POSTGRESQL_VERSIONS: "['postgres:12.14','postgres:15.2']" - PRE_COMMIT_CACHE: ~/.cache/pre-commit UV_CACHE_DIR: /tmp/uv-cache APT_CACHE_BASE: /home/runner/work/apt APT_CACHE_DIR: /home/runner/work/apt/cache @@ -83,7 +82,6 @@ jobs: integrations_glob: ${{ steps.info.outputs.integrations_glob }} integrations: ${{ steps.integrations.outputs.changes }} apt_cache_key: ${{ steps.generate_apt_cache_key.outputs.key }} - pre-commit_cache_key: ${{ steps.generate_pre-commit_cache_key.outputs.key }} python_cache_key: ${{ steps.generate_python_cache_key.outputs.key }} requirements: ${{ steps.core.outputs.requirements }} mariadb_groups: ${{ steps.info.outputs.mariadb_groups }} @@ -111,11 +109,6 @@ jobs: hashFiles('requirements_all.txt') }}-${{ hashFiles('homeassistant/package_constraints.txt') }}-${{ hashFiles('script/gen_requirements_all.py') }}" >> $GITHUB_OUTPUT - - name: Generate partial pre-commit restore key - id: generate_pre-commit_cache_key - run: >- - echo "key=pre-commit-${{ env.CACHE_VERSION }}-${{ - hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT - name: Generate partial apt restore key id: generate_apt_cache_key run: | @@ -244,8 +237,8 @@ jobs: echo "skip_coverage: ${skip_coverage}" echo "skip_coverage=${skip_coverage}" >> $GITHUB_OUTPUT - pre-commit: - name: Prepare pre-commit base + prek: + name: Run prek checks runs-on: *runs-on-ubuntu needs: [info] if: | @@ -254,147 +247,17 @@ jobs: && github.event.inputs.audit-licenses-only != 'true' steps: - *checkout - - &setup-python-default - name: Set up Python ${{ env.DEFAULT_PYTHON }} - id: python - uses: &actions-setup-python actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 - with: - python-version: ${{ env.DEFAULT_PYTHON }} - check-latest: true - - name: Restore base Python virtual environment - id: cache-venv - uses: &actions-cache actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: venv - key: &key-pre-commit-venv >- - ${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-venv-${{ - needs.info.outputs.pre-commit_cache_key }} - - name: Create Python virtual environment - if: steps.cache-venv.outputs.cache-hit != 'true' - run: | - python -m venv venv - . venv/bin/activate - python --version - pip install "$(grep '^uv' < requirements.txt)" - uv pip install "$(cat requirements_test.txt | grep pre-commit)" - - name: Restore pre-commit environment from cache - id: cache-precommit - uses: *actions-cache - with: - path: ${{ env.PRE_COMMIT_CACHE }} - lookup-only: true - key: &key-pre-commit-env >- - ${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-${{ - needs.info.outputs.pre-commit_cache_key }} - - name: Install pre-commit dependencies - if: steps.cache-precommit.outputs.cache-hit != 'true' - run: | - . venv/bin/activate - pre-commit install-hooks - - lint-ruff-format: - name: Check ruff-format - runs-on: *runs-on-ubuntu - needs: &needs-pre-commit - - info - - pre-commit - steps: - - *checkout - - *setup-python-default - - &cache-restore-pre-commit-venv - name: Restore base Python virtual environment - id: cache-venv - uses: &actions-cache-restore actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 - with: - path: venv - fail-on-cache-miss: true - key: *key-pre-commit-venv - - &cache-restore-pre-commit-env - name: Restore pre-commit environment from cache - id: cache-precommit - uses: *actions-cache-restore - with: - path: ${{ env.PRE_COMMIT_CACHE }} - fail-on-cache-miss: true - key: *key-pre-commit-env - - name: Run ruff-format - run: | - . venv/bin/activate - pre-commit run --hook-stage manual ruff-format --all-files --show-diff-on-failure - env: - RUFF_OUTPUT_FORMAT: github - - lint-ruff: - name: Check ruff - runs-on: *runs-on-ubuntu - needs: *needs-pre-commit - steps: - - *checkout - - *setup-python-default - - *cache-restore-pre-commit-venv - - *cache-restore-pre-commit-env - - name: Run ruff - run: | - . venv/bin/activate - pre-commit run --hook-stage manual ruff-check --all-files --show-diff-on-failure - env: - RUFF_OUTPUT_FORMAT: github - - lint-other: - name: Check other linters - runs-on: *runs-on-ubuntu - needs: *needs-pre-commit - steps: - - *checkout - - *setup-python-default - - *cache-restore-pre-commit-venv - - *cache-restore-pre-commit-env - - - name: Register yamllint problem matcher + - name: Register problem matchers run: | echo "::add-matcher::.github/workflows/matchers/yamllint.json" - - name: Run yamllint - run: | - . venv/bin/activate - pre-commit run --hook-stage manual yamllint --all-files --show-diff-on-failure - - - name: Register check-json problem matcher - run: | echo "::add-matcher::.github/workflows/matchers/check-json.json" - - name: Run check-json - run: | - . venv/bin/activate - pre-commit run --hook-stage manual check-json --all-files --show-diff-on-failure - - - name: Run prettier (fully) - if: needs.info.outputs.test_full_suite == 'true' - run: | - . venv/bin/activate - pre-commit run --hook-stage manual prettier --all-files --show-diff-on-failure - - - name: Run prettier (partially) - if: needs.info.outputs.test_full_suite == 'false' - shell: bash - run: | - . venv/bin/activate - shopt -s globstar - pre-commit run --hook-stage manual prettier --show-diff-on-failure --files {homeassistant,tests}/components/${{ needs.info.outputs.integrations_glob }}/{*,**/*} - - - name: Register check executables problem matcher - run: | echo "::add-matcher::.github/workflows/matchers/check-executables-have-shebangs.json" - - name: Run executables check - run: | - . venv/bin/activate - pre-commit run --hook-stage manual check-executables-have-shebangs --all-files --show-diff-on-failure - - - name: Register codespell problem matcher - run: | echo "::add-matcher::.github/workflows/matchers/codespell.json" - - name: Run codespell - run: | - . venv/bin/activate - pre-commit run --show-diff-on-failure --hook-stage manual codespell --all-files + - name: Run prek + uses: j178/prek-action@9d6a3097e0c1865ecce00cfb89fe80f2ee91b547 # v1.0.12 + env: + PREK_SKIP: no-commit-to-branch,mypy,pylint,gen_requirements_all,hassfest,hassfest-metadata,hassfest-mypy-config + RUFF_OUTPUT_FORMAT: github lint-hadolint: name: Check ${{ matrix.file }} @@ -434,7 +297,7 @@ jobs: - &setup-python-matrix name: Set up Python ${{ matrix.python-version }} id: python - uses: *actions-setup-python + uses: &actions-setup-python actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: python-version: ${{ matrix.python-version }} check-latest: true @@ -447,7 +310,7 @@ jobs: env.HA_SHORT_VERSION }}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT - name: Restore base Python virtual environment id: cache-venv - uses: *actions-cache + uses: &actions-cache actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 with: path: venv key: &key-python-venv >- @@ -511,7 +374,7 @@ jobs: fi - name: Save apt cache if: steps.cache-apt-check.outputs.cache-hit != 'true' - uses: &actions-cache-save actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 + uses: &actions-cache-save actions/cache/save@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 with: path: *path-apt-cache key: *key-apt-cache @@ -562,7 +425,7 @@ jobs: steps: - &cache-restore-apt name: Restore apt cache - uses: *actions-cache-restore + uses: &actions-cache-restore actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 with: path: *path-apt-cache fail-on-cache-miss: true @@ -579,7 +442,13 @@ jobs: -o Dir::State::Lists=${{ env.APT_LIST_CACHE_DIR }} \ libturbojpeg - *checkout - - *setup-python-default + - &setup-python-default + name: Set up Python ${{ env.DEFAULT_PYTHON }} + id: python + uses: *actions-setup-python + with: + python-version: ${{ env.DEFAULT_PYTHON }} + check-latest: true - &cache-restore-python-default name: Restore full Python ${{ env.DEFAULT_PYTHON }} virtual environment id: cache-venv @@ -782,9 +651,7 @@ jobs: - base - gen-requirements-all - hassfest - - lint-other - - lint-ruff - - lint-ruff-format + - prek - mypy steps: - *cache-restore-apt @@ -823,9 +690,7 @@ jobs: - base - gen-requirements-all - hassfest - - lint-other - - lint-ruff - - lint-ruff-format + - prek - mypy - prepare-pytest-full if: | @@ -949,9 +814,7 @@ jobs: - base - gen-requirements-all - hassfest - - lint-other - - lint-ruff - - lint-ruff-format + - prek - mypy if: | needs.info.outputs.lint_only != 'true' @@ -1066,9 +929,7 @@ jobs: - base - gen-requirements-all - hassfest - - lint-other - - lint-ruff - - lint-ruff-format + - prek - mypy if: | needs.info.outputs.lint_only != 'true' @@ -1202,9 +1063,7 @@ jobs: - base - gen-requirements-all - hassfest - - lint-other - - lint-ruff - - lint-ruff-format + - prek - mypy if: | needs.info.outputs.lint_only != 'true' @@ -1328,6 +1187,8 @@ jobs: - pytest-postgres - pytest-mariadb timeout-minutes: 10 + permissions: + id-token: write # codecov/test-results-action currently doesn't support tokenless uploads # therefore we can't run it on forks if: | @@ -1339,8 +1200,9 @@ jobs: with: pattern: test-results-* - name: Upload test results to Codecov - uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: + report_type: test_results fail_ci_if_error: true verbose: true - token: ${{ secrets.CODECOV_TOKEN }} + use_oidc: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2f3c48be0ba..aa094507e46 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,11 +24,11 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 with: languages: python - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9 + uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 with: category: "/language:python" diff --git a/.github/workflows/detect-duplicate-issues.yml b/.github/workflows/detect-duplicate-issues.yml index 055aab92b2b..ee58cd1e9e8 100644 --- a/.github/workflows/detect-duplicate-issues.yml +++ b/.github/workflows/detect-duplicate-issues.yml @@ -231,7 +231,7 @@ jobs: - name: Detect duplicates using AI id: ai_detection if: steps.extract.outputs.should_continue == 'true' && steps.fetch_similar.outputs.has_similar == 'true' - uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4 + uses: actions/ai-inference@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5 with: model: openai/gpt-4o system-prompt: | diff --git a/.github/workflows/detect-non-english-issues.yml b/.github/workflows/detect-non-english-issues.yml index a5e373b9ee6..fab2ee99219 100644 --- a/.github/workflows/detect-non-english-issues.yml +++ b/.github/workflows/detect-non-english-issues.yml @@ -57,7 +57,7 @@ jobs: - name: Detect language using AI id: ai_language_detection if: steps.detect_language.outputs.should_continue == 'true' - uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4 + uses: actions/ai-inference@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5 with: model: openai/gpt-4o-mini system-prompt: | diff --git a/.github/workflows/matchers/check-executables-have-shebangs.json b/.github/workflows/matchers/check-executables-have-shebangs.json index 667ef795632..1ff6ae0e94c 100644 --- a/.github/workflows/matchers/check-executables-have-shebangs.json +++ b/.github/workflows/matchers/check-executables-have-shebangs.json @@ -4,7 +4,7 @@ "owner": "check-executables-have-shebangs", "pattern": [ { - "regexp": "^(.+):\\s(.+)$", + "regexp": "^(.+):\\s(marked executable but has no \\(or invalid\\) shebang!.*)$", "file": 1, "message": 2 } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0d0b9cd27ba..152719ddf01 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,14 +39,14 @@ repos: - id: prettier additional_dependencies: - prettier@3.6.2 - - prettier-plugin-sort-json@4.1.1 + - prettier-plugin-sort-json@4.2.0 - repo: https://github.com/cdce8p/python-typing-update rev: v0.6.0 hooks: # Run `python-typing-update` hook manually from time to time # to update python typing syntax. # Will require manual work, before submitting changes! - # pre-commit run --hook-stage manual python-typing-update --all-files + # prek run --hook-stage manual python-typing-update --all-files - id: python-typing-update stages: [manual] args: diff --git a/.strict-typing b/.strict-typing index 91d91103c91..625f80e38c0 100644 --- a/.strict-typing +++ b/.strict-typing @@ -407,6 +407,7 @@ homeassistant.components.person.* homeassistant.components.pi_hole.* homeassistant.components.ping.* homeassistant.components.plugwise.* +homeassistant.components.pooldose.* homeassistant.components.portainer.* homeassistant.components.powerfox.* homeassistant.components.powerwall.* @@ -454,6 +455,7 @@ homeassistant.components.russound_rio.* homeassistant.components.ruuvi_gateway.* homeassistant.components.ruuvitag_ble.* homeassistant.components.samsungtv.* +homeassistant.components.saunum.* homeassistant.components.scene.* homeassistant.components.schedule.* homeassistant.components.schlage.* diff --git a/.vscode/settings.default.jsonc b/.vscode/settings.default.jsonc index bee6d5ef521..28e65799c70 100644 --- a/.vscode/settings.default.jsonc +++ b/.vscode/settings.default.jsonc @@ -7,8 +7,8 @@ "python.testing.pytestEnabled": false, // https://code.visualstudio.com/docs/python/linting#_general-settings "pylint.importStrategy": "fromEnvironment", - // Pyright is too pedantic for Home Assistant - "python.analysis.typeCheckingMode": "basic", + // Pyright type checking is not compatible with mypy which Home Assistant uses for type checking + "python.analysis.typeCheckingMode": "off", "[python]": { "editor.defaultFormatter": "charliermarsh.ruff", }, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 50bb89daf38..f66159370f4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -45,7 +45,7 @@ { "label": "Ruff", "type": "shell", - "command": "pre-commit run ruff-check --all-files", + "command": "prek run ruff-check --all-files", "group": { "kind": "test", "isDefault": true @@ -57,9 +57,9 @@ "problemMatcher": [] }, { - "label": "Pre-commit", + "label": "Prek", "type": "shell", - "command": "pre-commit run --show-diff-on-failure", + "command": "prek run --show-diff-on-failure", "group": { "kind": "test", "isDefault": true @@ -120,7 +120,7 @@ { "label": "Generate Requirements", "type": "shell", - "command": "./script/gen_requirements_all.py", + "command": "${command:python.interpreterPath} -m script.gen_requirements_all", "group": { "kind": "build", "isDefault": true diff --git a/CODEOWNERS b/CODEOWNERS index b6459c82ac8..949b8ff0b91 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1017,8 +1017,8 @@ build.json @home-assistant/supervisor /tests/components/mill/ @danielhiversen /homeassistant/components/min_max/ @gjohansson-ST /tests/components/min_max/ @gjohansson-ST -/homeassistant/components/minecraft_server/ @elmurato -/tests/components/minecraft_server/ @elmurato +/homeassistant/components/minecraft_server/ @elmurato @zachdeibert +/tests/components/minecraft_server/ @elmurato @zachdeibert /homeassistant/components/minio/ @tkislan /tests/components/minio/ @tkislan /homeassistant/components/moat/ @bdraco @@ -1068,6 +1068,8 @@ build.json @home-assistant/supervisor /tests/components/myuplink/ @pajzo @astrandb /homeassistant/components/nam/ @bieniu /tests/components/nam/ @bieniu +/homeassistant/components/namecheapdns/ @tr4nt0r +/tests/components/namecheapdns/ @tr4nt0r /homeassistant/components/nanoleaf/ @milanmeu @joostlek /tests/components/nanoleaf/ @milanmeu @joostlek /homeassistant/components/nasweb/ @nasWebio @@ -1271,7 +1273,8 @@ build.json @home-assistant/supervisor /tests/components/prosegur/ @dgomes /homeassistant/components/proximity/ @mib1185 /tests/components/proximity/ @mib1185 -/homeassistant/components/proxmoxve/ @jhollowe @Corbeno +/homeassistant/components/proxmoxve/ @jhollowe @Corbeno @erwindouna +/tests/components/proxmoxve/ @jhollowe @Corbeno @erwindouna /homeassistant/components/ps4/ @ktnrg45 /tests/components/ps4/ @ktnrg45 /homeassistant/components/pterodactyl/ @elmurato diff --git a/homeassistant/components/adguard/entity.py b/homeassistant/components/adguard/entity.py index 65d20a4e88c..bdc89e23f57 100644 --- a/homeassistant/components/adguard/entity.py +++ b/homeassistant/components/adguard/entity.py @@ -52,7 +52,7 @@ class AdGuardHomeEntity(Entity): def device_info(self) -> DeviceInfo: """Return device information about this AdGuard Home instance.""" if self._entry.source == SOURCE_HASSIO: - config_url = "homeassistant://hassio/ingress/a0d7b954_adguard" + config_url = "homeassistant://app/a0d7b954_adguard" elif self.adguard.tls: config_url = f"https://{self.adguard.host}:{self.adguard.port}" else: diff --git a/homeassistant/components/airobot/__init__.py b/homeassistant/components/airobot/__init__.py index 9cfb819b90d..abd3f5e53b3 100644 --- a/homeassistant/components/airobot/__init__.py +++ b/homeassistant/components/airobot/__init__.py @@ -12,6 +12,7 @@ PLATFORMS: list[Platform] = [ Platform.CLIMATE, Platform.NUMBER, Platform.SENSOR, + Platform.SWITCH, ] diff --git a/homeassistant/components/airobot/button.py b/homeassistant/components/airobot/button.py index fba02b6fe1e..6768fa4cf9b 100644 --- a/homeassistant/components/airobot/button.py +++ b/homeassistant/components/airobot/button.py @@ -43,6 +43,13 @@ BUTTON_TYPES: tuple[AirobotButtonEntityDescription, ...] = ( entity_category=EntityCategory.CONFIG, press_fn=lambda coordinator: coordinator.client.reboot_thermostat(), ), + AirobotButtonEntityDescription( + key="recalibrate_co2", + translation_key="recalibrate_co2", + entity_category=EntityCategory.CONFIG, + entity_registry_enabled_default=False, + press_fn=lambda coordinator: coordinator.client.recalibrate_co2_sensor(), + ), ) diff --git a/homeassistant/components/airobot/climate.py b/homeassistant/components/airobot/climate.py index 36dc90cf82e..9da653509f9 100644 --- a/homeassistant/components/airobot/climate.py +++ b/homeassistant/components/airobot/climate.py @@ -63,6 +63,11 @@ class AirobotClimate(AirobotEntity, ClimateEntity): _attr_min_temp = SETPOINT_TEMP_MIN _attr_max_temp = SETPOINT_TEMP_MAX + def __init__(self, coordinator) -> None: + """Initialize the climate entity.""" + super().__init__(coordinator) + self._attr_unique_id = coordinator.data.status.device_id + @property def _status(self) -> ThermostatStatus: """Get status from coordinator data.""" diff --git a/homeassistant/components/airobot/entity.py b/homeassistant/components/airobot/entity.py index 7a72e42364a..98a00d20c4b 100644 --- a/homeassistant/components/airobot/entity.py +++ b/homeassistant/components/airobot/entity.py @@ -24,8 +24,6 @@ class AirobotEntity(CoordinatorEntity[AirobotDataUpdateCoordinator]): status = coordinator.data.status settings = coordinator.data.settings - self._attr_unique_id = status.device_id - connections = set() if (mac := coordinator.config_entry.data.get(CONF_MAC)) is not None: connections.add((CONNECTION_NETWORK_MAC, mac)) diff --git a/homeassistant/components/airobot/icons.json b/homeassistant/components/airobot/icons.json index 2ea387512e4..c230efb3707 100644 --- a/homeassistant/components/airobot/icons.json +++ b/homeassistant/components/airobot/icons.json @@ -1,9 +1,22 @@ { "entity": { + "button": { + "recalibrate_co2": { + "default": "mdi:molecule-co2" + } + }, "number": { "hysteresis_band": { "default": "mdi:delta" } + }, + "switch": { + "actuator_exercise_disabled": { + "default": "mdi:valve" + }, + "child_lock": { + "default": "mdi:lock" + } } } } diff --git a/homeassistant/components/airobot/strings.json b/homeassistant/components/airobot/strings.json index ac9f26b2e4c..ecccf553736 100644 --- a/homeassistant/components/airobot/strings.json +++ b/homeassistant/components/airobot/strings.json @@ -59,6 +59,11 @@ } }, "entity": { + "button": { + "recalibrate_co2": { + "name": "Recalibrate CO2 sensor" + } + }, "number": { "hysteresis_band": { "name": "Hysteresis band" @@ -80,6 +85,14 @@ "heating_uptime": { "name": "Heating uptime" } + }, + "switch": { + "actuator_exercise_disabled": { + "name": "Actuator exercise disabled" + }, + "child_lock": { + "name": "Child lock" + } } }, "exceptions": { @@ -100,6 +113,12 @@ }, "set_value_failed": { "message": "Failed to set value: {error}" + }, + "switch_turn_off_failed": { + "message": "Failed to turn off {switch}." + }, + "switch_turn_on_failed": { + "message": "Failed to turn on {switch}." } } } diff --git a/homeassistant/components/airobot/switch.py b/homeassistant/components/airobot/switch.py new file mode 100644 index 00000000000..3a7c5d8222d --- /dev/null +++ b/homeassistant/components/airobot/switch.py @@ -0,0 +1,118 @@ +"""Switch platform for Airobot thermostat.""" + +from __future__ import annotations + +from collections.abc import Callable, Coroutine +from dataclasses import dataclass +from typing import Any + +from pyairobotrest.exceptions import AirobotError + +from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import AirobotConfigEntry +from .const import DOMAIN +from .coordinator import AirobotDataUpdateCoordinator +from .entity import AirobotEntity + +PARALLEL_UPDATES = 0 + + +@dataclass(frozen=True, kw_only=True) +class AirobotSwitchEntityDescription(SwitchEntityDescription): + """Describes Airobot switch entity.""" + + is_on_fn: Callable[[AirobotDataUpdateCoordinator], bool] + turn_on_fn: Callable[[AirobotDataUpdateCoordinator], Coroutine[Any, Any, None]] + turn_off_fn: Callable[[AirobotDataUpdateCoordinator], Coroutine[Any, Any, None]] + + +SWITCH_TYPES: tuple[AirobotSwitchEntityDescription, ...] = ( + AirobotSwitchEntityDescription( + key="child_lock", + translation_key="child_lock", + entity_category=EntityCategory.CONFIG, + is_on_fn=lambda coordinator: ( + coordinator.data.settings.setting_flags.childlock_enabled + ), + turn_on_fn=lambda coordinator: coordinator.client.set_child_lock(True), + turn_off_fn=lambda coordinator: coordinator.client.set_child_lock(False), + ), + AirobotSwitchEntityDescription( + key="actuator_exercise_disabled", + translation_key="actuator_exercise_disabled", + entity_category=EntityCategory.CONFIG, + entity_registry_enabled_default=False, + is_on_fn=lambda coordinator: ( + coordinator.data.settings.setting_flags.actuator_exercise_disabled + ), + turn_on_fn=lambda coordinator: coordinator.client.toggle_actuator_exercise( + True + ), + turn_off_fn=lambda coordinator: coordinator.client.toggle_actuator_exercise( + False + ), + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: AirobotConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Airobot switch entities.""" + coordinator = entry.runtime_data + + async_add_entities( + AirobotSwitch(coordinator, description) for description in SWITCH_TYPES + ) + + +class AirobotSwitch(AirobotEntity, SwitchEntity): + """Representation of an Airobot switch.""" + + entity_description: AirobotSwitchEntityDescription + + def __init__( + self, + coordinator: AirobotDataUpdateCoordinator, + description: AirobotSwitchEntityDescription, + ) -> None: + """Initialize the switch.""" + super().__init__(coordinator) + self.entity_description = description + self._attr_unique_id = f"{coordinator.data.status.device_id}_{description.key}" + + @property + def is_on(self) -> bool: + """Return true if the switch is on.""" + return self.entity_description.is_on_fn(self.coordinator) + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the switch on.""" + try: + await self.entity_description.turn_on_fn(self.coordinator) + except AirobotError as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="switch_turn_on_failed", + translation_placeholders={"switch": self.entity_description.key}, + ) from err + await self.coordinator.async_request_refresh() + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the switch off.""" + try: + await self.entity_description.turn_off_fn(self.coordinator) + except AirobotError as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="switch_turn_off_failed", + translation_placeholders={"switch": self.entity_description.key}, + ) from err + await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/airzone/entity.py b/homeassistant/components/airzone/entity.py index c0d7901981b..7513eec8a75 100644 --- a/homeassistant/components/airzone/entity.py +++ b/homeassistant/components/airzone/entity.py @@ -85,6 +85,22 @@ class AirzoneSystemEntity(AirzoneEntity): value = system[key] return value + async def _async_update_sys_params(self, params: dict[str, Any]) -> None: + """Send system parameters to API.""" + _params = { + API_SYSTEM_ID: self.system_id, + **params, + } + _LOGGER.debug("update_sys_params=%s", _params) + try: + await self.coordinator.airzone.set_sys_parameters(_params) + except AirzoneError as error: + raise HomeAssistantError( + f"Failed to set system {self.entity_id}: {error}" + ) from error + + self.coordinator.async_set_updated_data(self.coordinator.airzone.data()) + class AirzoneHotWaterEntity(AirzoneEntity): """Define an Airzone Hot Water entity.""" diff --git a/homeassistant/components/airzone/manifest.json b/homeassistant/components/airzone/manifest.json index d5aeeb7988d..b6f87438f3b 100644 --- a/homeassistant/components/airzone/manifest.json +++ b/homeassistant/components/airzone/manifest.json @@ -12,5 +12,5 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["aioairzone"], - "requirements": ["aioairzone==1.0.4"] + "requirements": ["aioairzone==1.0.5"] } diff --git a/homeassistant/components/airzone/select.py b/homeassistant/components/airzone/select.py index 813ead8b6a8..fe259c190ff 100644 --- a/homeassistant/components/airzone/select.py +++ b/homeassistant/components/airzone/select.py @@ -20,6 +20,7 @@ from aioairzone.const import ( AZD_MODES, AZD_Q_ADAPT, AZD_SLEEP, + AZD_SYSTEMS, AZD_ZONES, ) @@ -30,7 +31,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .coordinator import AirzoneConfigEntry, AirzoneUpdateCoordinator -from .entity import AirzoneEntity, AirzoneZoneEntity +from .entity import AirzoneEntity, AirzoneSystemEntity, AirzoneZoneEntity @dataclass(frozen=True, kw_only=True) @@ -85,14 +86,7 @@ def main_zone_options( return [k for k, v in options.items() if v in modes] -MAIN_ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = ( - AirzoneSelectDescription( - api_param=API_MODE, - key=AZD_MODE, - options_dict=MODE_DICT, - options_fn=main_zone_options, - translation_key="modes", - ), +SYSTEM_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = ( AirzoneSelectDescription( api_param=API_Q_ADAPT, entity_category=EntityCategory.CONFIG, @@ -104,6 +98,17 @@ MAIN_ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = ( ) +MAIN_ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = ( + AirzoneSelectDescription( + api_param=API_MODE, + key=AZD_MODE, + options_dict=MODE_DICT, + options_fn=main_zone_options, + translation_key="modes", + ), +) + + ZONE_SELECT_TYPES: Final[tuple[AirzoneSelectDescription, ...]] = ( AirzoneSelectDescription( api_param=API_COLD_ANGLE, @@ -140,16 +145,37 @@ async def async_setup_entry( """Add Airzone select from a config_entry.""" coordinator = entry.runtime_data + added_systems: set[str] = set() added_zones: set[str] = set() def _async_entity_listener() -> None: """Handle additions of select.""" + entities: list[AirzoneBaseSelect] = [] + + systems_data = coordinator.data.get(AZD_SYSTEMS, {}) + received_systems = set(systems_data) + new_systems = received_systems - added_systems + if new_systems: + entities.extend( + AirzoneSystemSelect( + coordinator, + description, + entry, + system_id, + systems_data.get(system_id), + ) + for system_id in new_systems + for description in SYSTEM_SELECT_TYPES + if description.key in systems_data.get(system_id) + ) + added_systems.update(new_systems) + zones_data = coordinator.data.get(AZD_ZONES, {}) received_zones = set(zones_data) new_zones = received_zones - added_zones if new_zones: - entities: list[AirzoneZoneSelect] = [ + entities.extend( AirzoneZoneSelect( coordinator, description, @@ -161,8 +187,8 @@ async def async_setup_entry( for description in MAIN_ZONE_SELECT_TYPES if description.key in zones_data.get(system_zone_id) and zones_data.get(system_zone_id).get(AZD_MASTER) is True - ] - entities += [ + ) + entities.extend( AirzoneZoneSelect( coordinator, description, @@ -173,10 +199,11 @@ async def async_setup_entry( for system_zone_id in new_zones for description in ZONE_SELECT_TYPES if description.key in zones_data.get(system_zone_id) - ] - async_add_entities(entities) + ) added_zones.update(new_zones) + async_add_entities(entities) + entry.async_on_unload(coordinator.async_add_listener(_async_entity_listener)) _async_entity_listener() @@ -203,6 +230,38 @@ class AirzoneBaseSelect(AirzoneEntity, SelectEntity): self._attr_current_option = self._get_current_option() +class AirzoneSystemSelect(AirzoneSystemEntity, AirzoneBaseSelect): + """Define an Airzone System select.""" + + def __init__( + self, + coordinator: AirzoneUpdateCoordinator, + description: AirzoneSelectDescription, + entry: ConfigEntry, + system_id: str, + system_data: dict[str, Any], + ) -> None: + """Initialize.""" + super().__init__(coordinator, entry, system_data) + + self._attr_unique_id = f"{self._attr_unique_id}_{system_id}_{description.key}" + self.entity_description = description + + self._attr_options = self.entity_description.options_fn( + system_data, description.options_dict + ) + + self.values_dict = {v: k for k, v in description.options_dict.items()} + + self._async_update_attrs() + + async def async_select_option(self, option: str) -> None: + """Change the selected option.""" + param = self.entity_description.api_param + value = self.entity_description.options_dict[option] + await self._async_update_sys_params({param: value}) + + class AirzoneZoneSelect(AirzoneZoneEntity, AirzoneBaseSelect): """Define an Airzone Zone select.""" diff --git a/homeassistant/components/alarm_control_panel/condition.py b/homeassistant/components/alarm_control_panel/condition.py new file mode 100644 index 00000000000..b1d3da3488b --- /dev/null +++ b/homeassistant/components/alarm_control_panel/condition.py @@ -0,0 +1,93 @@ +"""Provides conditions for alarm control panels.""" + +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.condition import ( + Condition, + EntityStateConditionBase, + make_entity_state_condition, +) +from homeassistant.helpers.entity import get_supported_features + +from .const import DOMAIN, AlarmControlPanelEntityFeature, AlarmControlPanelState + + +def supports_feature(hass: HomeAssistant, entity_id: str, features: int) -> bool: + """Test if an entity supports the specified features.""" + try: + return bool(get_supported_features(hass, entity_id) & features) + except HomeAssistantError: + return False + + +class EntityStateRequiredFeaturesCondition(EntityStateConditionBase): + """State condition.""" + + _required_features: int + + def entity_filter(self, entities: set[str]) -> set[str]: + """Filter entities of this domain with the required features.""" + entities = super().entity_filter(entities) + return { + entity_id + for entity_id in entities + if supports_feature(self._hass, entity_id, self._required_features) + } + + +def make_entity_state_required_features_condition( + domain: str, to_state: str, required_features: int +) -> type[EntityStateRequiredFeaturesCondition]: + """Create an entity state condition class with required feature filtering.""" + + class CustomCondition(EntityStateRequiredFeaturesCondition): + """Condition for entity state changes.""" + + _domain = domain + _states = {to_state} + _required_features = required_features + + return CustomCondition + + +CONDITIONS: dict[str, type[Condition]] = { + "is_armed": make_entity_state_condition( + DOMAIN, + { + AlarmControlPanelState.ARMED_AWAY, + AlarmControlPanelState.ARMED_CUSTOM_BYPASS, + AlarmControlPanelState.ARMED_HOME, + AlarmControlPanelState.ARMED_NIGHT, + AlarmControlPanelState.ARMED_VACATION, + }, + ), + "is_armed_away": make_entity_state_required_features_condition( + DOMAIN, + AlarmControlPanelState.ARMED_AWAY, + AlarmControlPanelEntityFeature.ARM_AWAY, + ), + "is_armed_home": make_entity_state_required_features_condition( + DOMAIN, + AlarmControlPanelState.ARMED_HOME, + AlarmControlPanelEntityFeature.ARM_HOME, + ), + "is_armed_night": make_entity_state_required_features_condition( + DOMAIN, + AlarmControlPanelState.ARMED_NIGHT, + AlarmControlPanelEntityFeature.ARM_NIGHT, + ), + "is_armed_vacation": make_entity_state_required_features_condition( + DOMAIN, + AlarmControlPanelState.ARMED_VACATION, + AlarmControlPanelEntityFeature.ARM_VACATION, + ), + "is_disarmed": make_entity_state_condition(DOMAIN, AlarmControlPanelState.DISARMED), + "is_triggered": make_entity_state_condition( + DOMAIN, AlarmControlPanelState.TRIGGERED + ), +} + + +async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]: + """Return the alarm control panel conditions.""" + return CONDITIONS diff --git a/homeassistant/components/alarm_control_panel/conditions.yaml b/homeassistant/components/alarm_control_panel/conditions.yaml new file mode 100644 index 00000000000..12c5b700b32 --- /dev/null +++ b/homeassistant/components/alarm_control_panel/conditions.yaml @@ -0,0 +1,52 @@ +.condition_common: &condition_common + target: + entity: + domain: alarm_control_panel + fields: &condition_common_fields + behavior: + required: true + default: any + selector: + select: + translation_key: condition_behavior + options: + - all + - any + +is_armed: *condition_common + +is_armed_away: + fields: *condition_common_fields + target: + entity: + domain: alarm_control_panel + supported_features: + - alarm_control_panel.AlarmControlPanelEntityFeature.ARM_AWAY + +is_armed_home: + fields: *condition_common_fields + target: + entity: + domain: alarm_control_panel + supported_features: + - alarm_control_panel.AlarmControlPanelEntityFeature.ARM_HOME + +is_armed_night: + fields: *condition_common_fields + target: + entity: + domain: alarm_control_panel + supported_features: + - alarm_control_panel.AlarmControlPanelEntityFeature.ARM_NIGHT + +is_armed_vacation: + fields: *condition_common_fields + target: + entity: + domain: alarm_control_panel + supported_features: + - alarm_control_panel.AlarmControlPanelEntityFeature.ARM_VACATION + +is_disarmed: *condition_common + +is_triggered: *condition_common diff --git a/homeassistant/components/alarm_control_panel/icons.json b/homeassistant/components/alarm_control_panel/icons.json index 0fbaeb59cf5..b7db7d4fffd 100644 --- a/homeassistant/components/alarm_control_panel/icons.json +++ b/homeassistant/components/alarm_control_panel/icons.json @@ -1,4 +1,27 @@ { + "conditions": { + "is_armed": { + "condition": "mdi:shield" + }, + "is_armed_away": { + "condition": "mdi:shield-lock" + }, + "is_armed_home": { + "condition": "mdi:shield-home" + }, + "is_armed_night": { + "condition": "mdi:shield-moon" + }, + "is_armed_vacation": { + "condition": "mdi:shield-airplane" + }, + "is_disarmed": { + "condition": "mdi:shield-off" + }, + "is_triggered": { + "condition": "mdi:bell-ring" + } + }, "entity_component": { "_": { "default": "mdi:shield", diff --git a/homeassistant/components/alarm_control_panel/strings.json b/homeassistant/components/alarm_control_panel/strings.json index 94567d69f3e..88d203193c3 100644 --- a/homeassistant/components/alarm_control_panel/strings.json +++ b/homeassistant/components/alarm_control_panel/strings.json @@ -1,8 +1,82 @@ { "common": { + "condition_behavior_description": "How the state should match on the targeted alarms.", + "condition_behavior_name": "Behavior", "trigger_behavior_description": "The behavior of the targeted alarms to trigger on.", "trigger_behavior_name": "Behavior" }, + "conditions": { + "is_armed": { + "description": "Tests if one or more alarms are armed.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is armed" + }, + "is_armed_away": { + "description": "Tests if one or more alarms are armed in away mode.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is armed away" + }, + "is_armed_home": { + "description": "Tests if one or more alarms are armed in home mode.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is armed home" + }, + "is_armed_night": { + "description": "Tests if one or more alarms are armed in night mode.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is armed night" + }, + "is_armed_vacation": { + "description": "Tests if one or more alarms are armed in vacation mode.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is armed vacation" + }, + "is_disarmed": { + "description": "Tests if one or more alarms are disarmed.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is disarmed" + }, + "is_triggered": { + "description": "Tests if one or more alarms are triggered.", + "fields": { + "behavior": { + "description": "[%key:component::alarm_control_panel::common::condition_behavior_description%]", + "name": "[%key:component::alarm_control_panel::common::condition_behavior_name%]" + } + }, + "name": "If an alarm is triggered" + } + }, "device_automation": { "action_type": { "arm_away": "Arm {entity_name} away", @@ -76,6 +150,12 @@ } }, "selector": { + "condition_behavior": { + "options": { + "all": "All", + "any": "Any" + } + }, "trigger_behavior": { "options": { "any": "Any", diff --git a/homeassistant/components/alarm_control_panel/trigger.py b/homeassistant/components/alarm_control_panel/trigger.py index 19302900823..d970ea9ec6b 100644 --- a/homeassistant/components/alarm_control_panel/trigger.py +++ b/homeassistant/components/alarm_control_panel/trigger.py @@ -14,7 +14,7 @@ from .const import DOMAIN, AlarmControlPanelEntityFeature, AlarmControlPanelStat def supports_feature(hass: HomeAssistant, entity_id: str, features: int) -> bool: - """Get the device class of an entity or UNDEFINED if not found.""" + """Test if an entity supports the specified features.""" try: return bool(get_supported_features(hass, entity_id) & features) except HomeAssistantError: @@ -39,7 +39,7 @@ class EntityStateTriggerRequiredFeatures(EntityTargetStateTriggerBase): def make_entity_state_trigger_required_features( domain: str, to_state: str, required_features: int ) -> type[EntityTargetStateTriggerBase]: - """Create an entity state trigger class.""" + """Create an entity state trigger class with required feature filtering.""" class CustomTrigger(EntityStateTriggerRequiredFeatures): """Trigger for entity state changes.""" diff --git a/homeassistant/components/apcupsd/sensor.py b/homeassistant/components/apcupsd/sensor.py index 7fde54194e0..2f8acbc754c 100644 --- a/homeassistant/components/apcupsd/sensor.py +++ b/homeassistant/components/apcupsd/sensor.py @@ -4,6 +4,8 @@ from __future__ import annotations import logging +import dateutil + from homeassistant.components.automation import automations_with_entity from homeassistant.components.script import scripts_with_entity from homeassistant.components.sensor import ( @@ -179,6 +181,7 @@ SENSORS: dict[str, SensorEntityDescription] = { LAST_S_TEST: SensorEntityDescription( key=LAST_S_TEST, translation_key="last_self_test", + device_class=SensorDeviceClass.TIMESTAMP, ), "lastxfer": SensorEntityDescription( key="lastxfer", @@ -232,6 +235,7 @@ SENSORS: dict[str, SensorEntityDescription] = { "masterupd": SensorEntityDescription( key="masterupd", translation_key="master_update", + device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, ), "maxlinev": SensorEntityDescription( @@ -365,6 +369,7 @@ SENSORS: dict[str, SensorEntityDescription] = { "starttime": SensorEntityDescription( key="starttime", translation_key="startup_time", + device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, ), "statflag": SensorEntityDescription( @@ -416,16 +421,19 @@ SENSORS: dict[str, SensorEntityDescription] = { "xoffbat": SensorEntityDescription( key="xoffbat", translation_key="transfer_from_battery", + device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, ), "xoffbatt": SensorEntityDescription( key="xoffbatt", translation_key="transfer_from_battery", + device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, ), "xonbatt": SensorEntityDescription( key="xonbatt", translation_key="transfer_to_battery", + device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, ), } @@ -529,7 +537,13 @@ class APCUPSdSensor(APCUPSdEntity, SensorEntity): self._attr_native_value = None return - self._attr_native_value, inferred_unit = infer_unit(self.coordinator.data[key]) + data = self.coordinator.data[key] + + if self.entity_description.device_class == SensorDeviceClass.TIMESTAMP: + self._attr_native_value = dateutil.parser.parse(data) + return + + self._attr_native_value, inferred_unit = infer_unit(data) if not self.native_unit_of_measurement: self._attr_native_unit_of_measurement = inferred_unit diff --git a/homeassistant/components/assist_pipeline/audio_enhancer.py b/homeassistant/components/assist_pipeline/audio_enhancer.py index 18f00d58d8a..1fabc7790e7 100644 --- a/homeassistant/components/assist_pipeline/audio_enhancer.py +++ b/homeassistant/components/assist_pipeline/audio_enhancer.py @@ -3,9 +3,8 @@ from abc import ABC, abstractmethod from dataclasses import dataclass import logging -import math -from pysilero_vad import SileroVoiceActivityDetector +from pymicro_vad import MicroVad from pyspeex_noise import AudioProcessor from .const import BYTES_PER_CHUNK @@ -43,8 +42,8 @@ class AudioEnhancer(ABC): """Enhance chunk of PCM audio @ 16Khz with 16-bit mono samples.""" -class SileroVadSpeexEnhancer(AudioEnhancer): - """Audio enhancer that runs Silero VAD and speex.""" +class MicroVadSpeexEnhancer(AudioEnhancer): + """Audio enhancer that runs microVAD and speex.""" def __init__( self, auto_gain: int, noise_suppression: int, is_vad_enabled: bool @@ -70,49 +69,21 @@ class SileroVadSpeexEnhancer(AudioEnhancer): self.noise_suppression, ) - self.vad: SileroVoiceActivityDetector | None = None - - # We get 10ms chunks but Silero works on 32ms chunks, so we have to - # buffer audio. The previous speech probability is used until enough - # audio has been buffered. - self._vad_buffer: bytearray | None = None - self._vad_buffer_chunks = 0 - self._vad_buffer_chunk_idx = 0 - self._last_speech_probability: float | None = None + self.vad: MicroVad | None = None if self.is_vad_enabled: - self.vad = SileroVoiceActivityDetector() - - # VAD buffer is a multiple of 10ms, but Silero VAD needs 32ms. - self._vad_buffer_chunks = int( - math.ceil(self.vad.chunk_bytes() / BYTES_PER_CHUNK) - ) - self._vad_leftover_bytes = self.vad.chunk_bytes() - BYTES_PER_CHUNK - self._vad_buffer = bytearray(self.vad.chunk_bytes()) - _LOGGER.debug("Initialized Silero VAD") + self.vad = MicroVad() + _LOGGER.debug("Initialized microVAD") def enhance_chunk(self, audio: bytes, timestamp_ms: int) -> EnhancedAudioChunk: """Enhance 10ms chunk of PCM audio @ 16Khz with 16-bit mono samples.""" + speech_probability: float | None = None + assert len(audio) == BYTES_PER_CHUNK if self.vad is not None: # Run VAD - assert self._vad_buffer is not None - start_idx = self._vad_buffer_chunk_idx * BYTES_PER_CHUNK - self._vad_buffer[start_idx : start_idx + BYTES_PER_CHUNK] = audio - - self._vad_buffer_chunk_idx += 1 - if self._vad_buffer_chunk_idx >= self._vad_buffer_chunks: - # We have enough data to run Silero VAD (32 ms) - self._last_speech_probability = self.vad.process_chunk( - self._vad_buffer[: self.vad.chunk_bytes()] - ) - - # Copy leftover audio that wasn't processed to start - self._vad_buffer[: self._vad_leftover_bytes] = self._vad_buffer[ - -self._vad_leftover_bytes : - ] - self._vad_buffer_chunk_idx = 0 + speech_probability = self.vad.Process10ms(audio) if self.audio_processor is not None: # Run noise suppression and auto gain @@ -121,5 +92,5 @@ class SileroVadSpeexEnhancer(AudioEnhancer): return EnhancedAudioChunk( audio=audio, timestamp_ms=timestamp_ms, - speech_probability=self._last_speech_probability, + speech_probability=speech_probability, ) diff --git a/homeassistant/components/assist_pipeline/manifest.json b/homeassistant/components/assist_pipeline/manifest.json index 98804877c2e..d88e4352130 100644 --- a/homeassistant/components/assist_pipeline/manifest.json +++ b/homeassistant/components/assist_pipeline/manifest.json @@ -8,5 +8,5 @@ "integration_type": "system", "iot_class": "local_push", "quality_scale": "internal", - "requirements": ["pysilero-vad==3.1.0", "pyspeex-noise==1.0.2"] + "requirements": ["pymicro-vad==1.0.1", "pyspeex-noise==1.0.2"] } diff --git a/homeassistant/components/assist_pipeline/pipeline.py b/homeassistant/components/assist_pipeline/pipeline.py index abfc4e72782..0948413d4cc 100644 --- a/homeassistant/components/assist_pipeline/pipeline.py +++ b/homeassistant/components/assist_pipeline/pipeline.py @@ -55,7 +55,7 @@ from homeassistant.util import ( from homeassistant.util.hass_dict import HassKey from homeassistant.util.limited_size_dict import LimitedSizeDict -from .audio_enhancer import AudioEnhancer, EnhancedAudioChunk, SileroVadSpeexEnhancer +from .audio_enhancer import AudioEnhancer, EnhancedAudioChunk, MicroVadSpeexEnhancer from .const import ( ACKNOWLEDGE_PATH, BYTES_PER_CHUNK, @@ -633,7 +633,7 @@ class PipelineRun: # Initialize with audio settings if self.audio_settings.needs_processor and (self.audio_enhancer is None): # Default audio enhancer - self.audio_enhancer = SileroVadSpeexEnhancer( + self.audio_enhancer = MicroVadSpeexEnhancer( self.audio_settings.auto_gain_dbfs, self.audio_settings.noise_suppression_level, self.audio_settings.is_vad_enabled, diff --git a/homeassistant/components/assist_satellite/condition.py b/homeassistant/components/assist_satellite/condition.py new file mode 100644 index 00000000000..0c0a402d6f5 --- /dev/null +++ b/homeassistant/components/assist_satellite/condition.py @@ -0,0 +1,23 @@ +"""Provides conditions for assist satellites.""" + +from homeassistant.core import HomeAssistant +from homeassistant.helpers.condition import Condition, make_entity_state_condition + +from .const import DOMAIN +from .entity import AssistSatelliteState + +CONDITIONS: dict[str, type[Condition]] = { + "is_idle": make_entity_state_condition(DOMAIN, AssistSatelliteState.IDLE), + "is_listening": make_entity_state_condition(DOMAIN, AssistSatelliteState.LISTENING), + "is_processing": make_entity_state_condition( + DOMAIN, AssistSatelliteState.PROCESSING + ), + "is_responding": make_entity_state_condition( + DOMAIN, AssistSatelliteState.RESPONDING + ), +} + + +async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]: + """Return the assist satellite conditions.""" + return CONDITIONS diff --git a/homeassistant/components/assist_satellite/conditions.yaml b/homeassistant/components/assist_satellite/conditions.yaml new file mode 100644 index 00000000000..eeb7f02b913 --- /dev/null +++ b/homeassistant/components/assist_satellite/conditions.yaml @@ -0,0 +1,19 @@ +.condition_common: &condition_common + target: + entity: + domain: assist_satellite + fields: + behavior: + required: true + default: any + selector: + select: + translation_key: condition_behavior + options: + - all + - any + +is_idle: *condition_common +is_listening: *condition_common +is_processing: *condition_common +is_responding: *condition_common diff --git a/homeassistant/components/assist_satellite/icons.json b/homeassistant/components/assist_satellite/icons.json index 975b943416d..c4f15d320de 100644 --- a/homeassistant/components/assist_satellite/icons.json +++ b/homeassistant/components/assist_satellite/icons.json @@ -1,4 +1,18 @@ { + "conditions": { + "is_idle": { + "condition": "mdi:chat-sleep" + }, + "is_listening": { + "condition": "mdi:chat-question" + }, + "is_processing": { + "condition": "mdi:chat-processing" + }, + "is_responding": { + "condition": "mdi:chat-alert" + } + }, "entity_component": { "_": { "default": "mdi:account-voice" diff --git a/homeassistant/components/assist_satellite/strings.json b/homeassistant/components/assist_satellite/strings.json index 95ce20a851c..4680df87f33 100644 --- a/homeassistant/components/assist_satellite/strings.json +++ b/homeassistant/components/assist_satellite/strings.json @@ -1,8 +1,52 @@ { "common": { + "condition_behavior_description": "How the state should match on the targeted Assist satellites.", + "condition_behavior_name": "Behavior", "trigger_behavior_description": "The behavior of the targeted Assist satellites to trigger on.", "trigger_behavior_name": "Behavior" }, + "conditions": { + "is_idle": { + "description": "Tests if one or more Assist satellites are idle.", + "fields": { + "behavior": { + "description": "[%key:component::assist_satellite::common::condition_behavior_description%]", + "name": "[%key:component::assist_satellite::common::condition_behavior_name%]" + } + }, + "name": "If a satellite is idle" + }, + "is_listening": { + "description": "Tests if one or more Assist satellites are listening.", + "fields": { + "behavior": { + "description": "[%key:component::assist_satellite::common::condition_behavior_description%]", + "name": "[%key:component::assist_satellite::common::condition_behavior_name%]" + } + }, + "name": "If a satellite is listening" + }, + "is_processing": { + "description": "Tests if one or more Assist satellites are processing.", + "fields": { + "behavior": { + "description": "[%key:component::assist_satellite::common::condition_behavior_description%]", + "name": "[%key:component::assist_satellite::common::condition_behavior_name%]" + } + }, + "name": "If a satellite is processing" + }, + "is_responding": { + "description": "Tests if one or more Assist satellites are responding.", + "fields": { + "behavior": { + "description": "[%key:component::assist_satellite::common::condition_behavior_description%]", + "name": "[%key:component::assist_satellite::common::condition_behavior_name%]" + } + }, + "name": "If a satellite is responding" + } + }, "entity_component": { "_": { "name": "Assist satellite", @@ -21,6 +65,12 @@ "sentences": "Sentences" } }, + "condition_behavior": { + "options": { + "all": "All", + "any": "Any" + } + }, "trigger_behavior": { "options": { "any": "Any", diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 5ce6fca7c2e..d56ca509a74 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -123,7 +123,11 @@ SERVICE_TRIGGER = "trigger" NEW_TRIGGERS_CONDITIONS_FEATURE_FLAG = "new_triggers_conditions" _EXPERIMENTAL_CONDITION_PLATFORMS = { + "alarm_control_panel", + "assist_satellite", + "fan", "light", + "siren", } _EXPERIMENTAL_TRIGGER_PLATFORMS = { @@ -598,6 +602,10 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): """Return a set of referenced labels.""" referenced = self.action_script.referenced_labels + if self._cond_func is not None: + for conf in self._cond_func.config: + referenced |= condition.async_extract_targets(conf, ATTR_LABEL_ID) + for conf in self._trigger_config: referenced |= set(_get_targets_from_trigger_config(conf, ATTR_LABEL_ID)) return referenced @@ -607,6 +615,10 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): """Return a set of referenced floors.""" referenced = self.action_script.referenced_floors + if self._cond_func is not None: + for conf in self._cond_func.config: + referenced |= condition.async_extract_targets(conf, ATTR_FLOOR_ID) + for conf in self._trigger_config: referenced |= set(_get_targets_from_trigger_config(conf, ATTR_FLOOR_ID)) return referenced @@ -616,6 +628,10 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): """Return a set of referenced areas.""" referenced = self.action_script.referenced_areas + if self._cond_func is not None: + for conf in self._cond_func.config: + referenced |= condition.async_extract_targets(conf, ATTR_AREA_ID) + for conf in self._trigger_config: referenced |= set(_get_targets_from_trigger_config(conf, ATTR_AREA_ID)) return referenced diff --git a/homeassistant/components/azure_service_bus/notify.py b/homeassistant/components/azure_service_bus/notify.py index 83eb8076fef..5943ec8f855 100644 --- a/homeassistant/components/azure_service_bus/notify.py +++ b/homeassistant/components/azure_service_bus/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations import json import logging +from typing import Any from azure.servicebus import ServiceBusMessage from azure.servicebus.aio import ServiceBusClient, ServiceBusSender @@ -92,7 +93,7 @@ class ServiceBusNotificationService(BaseNotificationService): """Initialize the service.""" self._client = client - async def async_send_message(self, message, **kwargs): + async def async_send_message(self, message: str, **kwargs: Any) -> None: """Send a message.""" dto = {ATTR_ASB_MESSAGE: message} diff --git a/homeassistant/components/binary_sensor/icons.json b/homeassistant/components/binary_sensor/icons.json index a457fa667ed..966e2adb5a1 100644 --- a/homeassistant/components/binary_sensor/icons.json +++ b/homeassistant/components/binary_sensor/icons.json @@ -85,9 +85,9 @@ } }, "moving": { - "default": "mdi:arrow-right", + "default": "mdi:octagon", "state": { - "on": "mdi:octagon" + "on": "mdi:arrow-right" } }, "occupancy": { diff --git a/homeassistant/components/blebox/sensor.py b/homeassistant/components/blebox/sensor.py index 5120a7a3c98..14cddf41e45 100644 --- a/homeassistant/components/blebox/sensor.py +++ b/homeassistant/components/blebox/sensor.py @@ -1,5 +1,7 @@ """BleBox sensor entities.""" +from datetime import datetime + import blebox_uniapi.sensor from homeassistant.components.sensor import ( @@ -146,7 +148,7 @@ class BleBoxSensorEntity(BleBoxEntity[blebox_uniapi.sensor.BaseSensor], SensorEn return self._feature.native_value @property - def last_reset(self): + def last_reset(self) -> datetime | None: """Return the time when the sensor was last reset, if implemented.""" native_implementation = getattr(self._feature, "last_reset", None) diff --git a/homeassistant/components/blueprint/websocket_api.py b/homeassistant/components/blueprint/websocket_api.py index 0743d027d8d..873e3b30a36 100644 --- a/homeassistant/components/blueprint/websocket_api.py +++ b/homeassistant/components/blueprint/websocket_api.py @@ -64,6 +64,7 @@ def _ws_with_blueprint_domain( return with_domain_blueprints +@websocket_api.require_admin @websocket_api.websocket_command( { vol.Required("type"): "blueprint/list", @@ -97,6 +98,7 @@ async def ws_list_blueprints( connection.send_result(msg["id"], results) +@websocket_api.require_admin @websocket_api.websocket_command( { vol.Required("type"): "blueprint/import", @@ -150,6 +152,7 @@ async def ws_import_blueprint( ) +@websocket_api.require_admin @websocket_api.websocket_command( { vol.Required("type"): "blueprint/save", @@ -206,6 +209,7 @@ async def ws_save_blueprint( ) +@websocket_api.require_admin @websocket_api.websocket_command( { vol.Required("type"): "blueprint/delete", @@ -233,6 +237,7 @@ async def ws_delete_blueprint( ) +@websocket_api.require_admin @websocket_api.websocket_command( { vol.Required("type"): "blueprint/substitute", diff --git a/homeassistant/components/bsblan/__init__.py b/homeassistant/components/bsblan/__init__.py index eaa0c1eebb6..1abe376826b 100644 --- a/homeassistant/components/bsblan/__init__.py +++ b/homeassistant/components/bsblan/__init__.py @@ -1,5 +1,6 @@ """The BSB-Lan integration.""" +import asyncio import dataclasses from bsblan import ( @@ -77,12 +78,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: BSBLanConfigEntry) -> bo bsblan = BSBLAN(config, session) try: - # Initialize the client first - this sets up internal caches and validates the connection + # Initialize the client first - this sets up internal caches and validates + # the connection by fetching firmware version await bsblan.initialize() - # Fetch all required device metadata - device = await bsblan.device() - info = await bsblan.info() - static = await bsblan.static_values() + + # Fetch device metadata in parallel for faster startup + device, info, static = await asyncio.gather( + bsblan.device(), + bsblan.info(), + bsblan.static_values(), + ) except BSBLANConnectionError as err: raise ConfigEntryNotReady( translation_domain=DOMAIN, @@ -110,10 +115,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: BSBLanConfigEntry) -> bo fast_coordinator = BSBLanFastCoordinator(hass, entry, bsblan) slow_coordinator = BSBLanSlowCoordinator(hass, entry, bsblan) - # Perform first refresh of both coordinators + # Perform first refresh of fast coordinator (required for entities) await fast_coordinator.async_config_entry_first_refresh() - # Try to refresh slow coordinator, but don't fail if DHW is not available + # Refresh slow coordinator - don't fail if DHW is not available # This allows the integration to work even if the device doesn't support DHW await slow_coordinator.async_refresh() diff --git a/homeassistant/components/bsblan/climate.py b/homeassistant/components/bsblan/climate.py index 71f2776d951..44767ff7bff 100644 --- a/homeassistant/components/bsblan/climate.py +++ b/homeassistant/components/bsblan/climate.py @@ -111,11 +111,17 @@ class BSBLANClimate(BSBLanEntity, ClimateEntity): return None return self.coordinator.data.state.target_temperature.value + @property + def _hvac_mode_value(self) -> int | str | None: + """Return the raw hvac_mode value from the coordinator.""" + if (hvac_mode := self.coordinator.data.state.hvac_mode) is None: + return None + return hvac_mode.value + @property def hvac_mode(self) -> HVACMode | None: """Return hvac operation ie. heat, cool mode.""" - hvac_mode_value = self.coordinator.data.state.hvac_mode.value - if hvac_mode_value is None: + if (hvac_mode_value := self._hvac_mode_value) is None: return None # BSB-Lan returns integer values: 0=off, 1=auto, 2=eco, 3=heat if isinstance(hvac_mode_value, int): @@ -125,9 +131,8 @@ class BSBLANClimate(BSBLanEntity, ClimateEntity): @property def preset_mode(self) -> str | None: """Return the current preset mode.""" - hvac_mode_value = self.coordinator.data.state.hvac_mode.value # BSB-Lan mode 2 is eco/reduced mode - if hvac_mode_value == 2: + if self._hvac_mode_value == 2: return PRESET_ECO return PRESET_NONE diff --git a/homeassistant/components/bsblan/coordinator.py b/homeassistant/components/bsblan/coordinator.py index 6b1ae70b338..b39376f6f02 100644 --- a/homeassistant/components/bsblan/coordinator.py +++ b/homeassistant/components/bsblan/coordinator.py @@ -2,7 +2,6 @@ from dataclasses import dataclass from datetime import timedelta -from random import randint from bsblan import ( BSBLAN, @@ -23,6 +22,17 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda from .const import DOMAIN, LOGGER, SCAN_INTERVAL_FAST, SCAN_INTERVAL_SLOW +# Filter lists for optimized API calls - only fetch parameters we actually use +# This significantly reduces response time (~0.2s per parameter saved) +STATE_INCLUDE = ["current_temperature", "target_temperature", "hvac_mode"] +SENSOR_INCLUDE = ["current_temperature", "outside_temperature"] +DHW_STATE_INCLUDE = [ + "operating_mode", + "nominal_setpoint", + "dhw_actual_value_top_temperature", +] +DHW_CONFIG_INCLUDE = ["reduced_setpoint", "nominal_setpoint_max"] + @dataclass class BSBLanFastData: @@ -80,26 +90,18 @@ class BSBLanFastCoordinator(BSBLanCoordinator[BSBLanFastData]): config_entry, client, name=f"{DOMAIN}_fast_{config_entry.data[CONF_HOST]}", - update_interval=self._get_update_interval(), + update_interval=SCAN_INTERVAL_FAST, ) - def _get_update_interval(self) -> timedelta: - """Get the update interval with a random offset. - - Add a random number of seconds to avoid timeouts when - the BSB-Lan device is already/still busy retrieving data, - e.g. for MQTT or internal logging. - """ - return SCAN_INTERVAL_FAST + timedelta(seconds=randint(1, 8)) - async def _async_update_data(self) -> BSBLanFastData: """Fetch fast-changing data from the BSB-Lan device.""" try: # Client is already initialized in async_setup_entry - # Fetch fast-changing data (state, sensor, DHW state) - state = await self.client.state() - sensor = await self.client.sensor() - dhw = await self.client.hot_water_state() + # Use include filtering to only fetch parameters we actually use + # This reduces response time significantly (~0.2s per parameter) + state = await self.client.state(include=STATE_INCLUDE) + sensor = await self.client.sensor(include=SENSOR_INCLUDE) + dhw = await self.client.hot_water_state(include=DHW_STATE_INCLUDE) except BSBLANAuthError as err: raise ConfigEntryAuthFailed( @@ -111,9 +113,6 @@ class BSBLanFastCoordinator(BSBLanCoordinator[BSBLanFastData]): f"Error while establishing connection with BSB-Lan device at {host}" ) from err - # Update the interval with random jitter for next update - self.update_interval = self._get_update_interval() - return BSBLanFastData( state=state, sensor=sensor, @@ -143,8 +142,8 @@ class BSBLanSlowCoordinator(BSBLanCoordinator[BSBLanSlowData]): """Fetch slow-changing data from the BSB-Lan device.""" try: # Client is already initialized in async_setup_entry - # Fetch slow-changing configuration data - dhw_config = await self.client.hot_water_config() + # Use include filtering to only fetch parameters we actually use + dhw_config = await self.client.hot_water_config(include=DHW_CONFIG_INCLUDE) dhw_schedule = await self.client.hot_water_schedule() except AttributeError: diff --git a/homeassistant/components/bsblan/entity.py b/homeassistant/components/bsblan/entity.py index b2effc9f3f4..5f5203ef8d0 100644 --- a/homeassistant/components/bsblan/entity.py +++ b/homeassistant/components/bsblan/entity.py @@ -29,7 +29,11 @@ class BSBLanEntityBase[_T: BSBLanCoordinator](CoordinatorEntity[_T]): connections={(CONNECTION_NETWORK_MAC, format_mac(mac))}, name=data.device.name, manufacturer="BSBLAN Inc.", - model=data.info.device_identification.value, + model=( + data.info.device_identification.value + if data.info.device_identification + else None + ), sw_version=data.device.version, configuration_url=f"http://{host}", ) diff --git a/homeassistant/components/bsblan/manifest.json b/homeassistant/components/bsblan/manifest.json index 4545e601719..fe581ef062f 100644 --- a/homeassistant/components/bsblan/manifest.json +++ b/homeassistant/components/bsblan/manifest.json @@ -7,7 +7,7 @@ "integration_type": "device", "iot_class": "local_polling", "loggers": ["bsblan"], - "requirements": ["python-bsblan==3.1.6"], + "requirements": ["python-bsblan==4.1.0"], "zeroconf": [ { "name": "bsb-lan*", diff --git a/homeassistant/components/bthome/manifest.json b/homeassistant/components/bthome/manifest.json index ae91ff19239..ca9744d5b63 100644 --- a/homeassistant/components/bthome/manifest.json +++ b/homeassistant/components/bthome/manifest.json @@ -20,5 +20,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/bthome", "iot_class": "local_push", - "requirements": ["bthome-ble==3.17.0"] + "requirements": ["bthome-ble==3.16.0"] } diff --git a/homeassistant/components/calendar/icons.json b/homeassistant/components/calendar/icons.json index 804a3a4b04f..e2faf13658c 100644 --- a/homeassistant/components/calendar/icons.json +++ b/homeassistant/components/calendar/icons.json @@ -15,5 +15,13 @@ "get_events": { "service": "mdi:calendar-month" } + }, + "triggers": { + "event_ended": { + "trigger": "mdi:calendar-end" + }, + "event_started": { + "trigger": "mdi:calendar-start" + } } } diff --git a/homeassistant/components/calendar/strings.json b/homeassistant/components/calendar/strings.json index c8117140d9d..b4169132e86 100644 --- a/homeassistant/components/calendar/strings.json +++ b/homeassistant/components/calendar/strings.json @@ -45,6 +45,14 @@ "title": "Detected use of deprecated action calendar.list_events" } }, + "selector": { + "trigger_offset_type": { + "options": { + "after": "After", + "before": "Before" + } + } + }, "services": { "create_event": { "description": "Adds a new calendar event.", @@ -103,5 +111,35 @@ "name": "Get events" } }, - "title": "Calendar" + "title": "Calendar", + "triggers": { + "event_ended": { + "description": "Triggers when a calendar event ends.", + "fields": { + "offset": { + "description": "Offset from the end of the event.", + "name": "Offset" + }, + "offset_type": { + "description": "Whether to trigger before or after the end of the event, if an offset is defined.", + "name": "Offset type" + } + }, + "name": "Calendar event ended" + }, + "event_started": { + "description": "Triggers when a calendar event starts.", + "fields": { + "offset": { + "description": "Offset from the start of the event.", + "name": "Offset" + }, + "offset_type": { + "description": "Whether to trigger before or after the start of the event, if an offset is defined.", + "name": "Offset type" + } + }, + "name": "Calendar event started" + } + } } diff --git a/homeassistant/components/calendar/trigger.py b/homeassistant/components/calendar/trigger.py index ec96d23a424..18ab33516e7 100644 --- a/homeassistant/components/calendar/trigger.py +++ b/homeassistant/components/calendar/trigger.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio from collections.abc import Awaitable, Callable from dataclasses import dataclass import datetime @@ -10,8 +11,15 @@ from typing import TYPE_CHECKING, Any, cast import voluptuous as vol -from homeassistant.const import CONF_ENTITY_ID, CONF_EVENT, CONF_OFFSET, CONF_OPTIONS -from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback +from homeassistant.const import ( + ATTR_ENTITY_ID, + CONF_ENTITY_ID, + CONF_EVENT, + CONF_OFFSET, + CONF_OPTIONS, + CONF_TARGET, +) +from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback, split_entity_id from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_validation as cv from homeassistant.helpers.automation import move_top_level_schema_fields_to_options @@ -20,12 +28,13 @@ from homeassistant.helpers.event import ( async_track_point_in_time, async_track_time_interval, ) +from homeassistant.helpers.target import TargetEntityChangeTracker, TargetSelection from homeassistant.helpers.trigger import Trigger, TriggerActionRunner, TriggerConfig from homeassistant.helpers.typing import ConfigType from homeassistant.util import dt as dt_util from . import CalendarEntity, CalendarEvent -from .const import DATA_COMPONENT +from .const import DATA_COMPONENT, DOMAIN _LOGGER = logging.getLogger(__name__) @@ -33,19 +42,35 @@ EVENT_START = "start" EVENT_END = "end" UPDATE_INTERVAL = datetime.timedelta(minutes=15) +CONF_OFFSET_TYPE = "offset_type" +OFFSET_TYPE_BEFORE = "before" +OFFSET_TYPE_AFTER = "after" -_OPTIONS_SCHEMA_DICT = { + +_SINGLE_ENTITY_EVENT_OPTIONS_SCHEMA = { vol.Required(CONF_ENTITY_ID): cv.entity_id, vol.Optional(CONF_EVENT, default=EVENT_START): vol.In({EVENT_START, EVENT_END}), vol.Optional(CONF_OFFSET, default=datetime.timedelta(0)): cv.time_period, } -_CONFIG_SCHEMA = vol.Schema( +_SINGLE_ENTITY_EVENT_TRIGGER_SCHEMA = vol.Schema( { - vol.Required(CONF_OPTIONS): _OPTIONS_SCHEMA_DICT, + vol.Required(CONF_OPTIONS): _SINGLE_ENTITY_EVENT_OPTIONS_SCHEMA, }, ) +_EVENT_TRIGGER_SCHEMA = vol.Schema( + { + vol.Required(CONF_OPTIONS, default={}): { + vol.Required(CONF_OFFSET, default=datetime.timedelta(0)): cv.time_period, + vol.Required(CONF_OFFSET_TYPE, default=OFFSET_TYPE_BEFORE): vol.In( + {OFFSET_TYPE_BEFORE, OFFSET_TYPE_AFTER} + ), + }, + vol.Required(CONF_TARGET): cv.TARGET_FIELDS, + } +) + # mypy: disallow-any-generics @@ -55,6 +80,7 @@ class QueuedCalendarEvent: trigger_time: datetime.datetime event: CalendarEvent + entity_id: str @dataclass @@ -94,7 +120,7 @@ class Timespan: return f"[{self.start}, {self.end})" -type EventFetcher = Callable[[Timespan], Awaitable[list[CalendarEvent]]] +type EventFetcher = Callable[[Timespan], Awaitable[list[tuple[str, CalendarEvent]]]] type QueuedEventFetcher = Callable[[Timespan], Awaitable[list[QueuedCalendarEvent]]] @@ -110,15 +136,24 @@ def get_entity(hass: HomeAssistant, entity_id: str) -> CalendarEntity: return entity -def event_fetcher(hass: HomeAssistant, entity_id: str) -> EventFetcher: +def event_fetcher(hass: HomeAssistant, entity_ids: set[str]) -> EventFetcher: """Build an async_get_events wrapper to fetch events during a time span.""" - async def async_get_events(timespan: Timespan) -> list[CalendarEvent]: + async def async_get_events(timespan: Timespan) -> list[tuple[str, CalendarEvent]]: """Return events active in the specified time span.""" - entity = get_entity(hass, entity_id) # Expand by one second to make the end time exclusive end_time = timespan.end + datetime.timedelta(seconds=1) - return await entity.async_get_events(hass, timespan.start, end_time) + + events: list[tuple[str, CalendarEvent]] = [] + for entity_id in entity_ids: + entity = get_entity(hass, entity_id) + events.extend( + (entity_id, event) + for event in await entity.async_get_events( + hass, timespan.start, end_time + ) + ) + return events return async_get_events @@ -142,12 +177,11 @@ def queued_event_fetcher( # Example: For an EVENT_END trigger the event may start during this # time span, but need to be triggered later when the end happens. results = [] - for trigger_time, event in zip( - map(get_trigger_time, active_events), active_events, strict=False - ): + for entity_id, event in active_events: + trigger_time = get_trigger_time(event) if trigger_time not in offset_timespan: continue - results.append(QueuedCalendarEvent(trigger_time + offset, event)) + results.append(QueuedCalendarEvent(trigger_time + offset, event, entity_id)) _LOGGER.debug( "Scan events @ %s%s found %s eligible of %s active", @@ -240,6 +274,7 @@ class CalendarEventListener: _LOGGER.debug("Dispatching event: %s", queued_event.event) payload = { **self._trigger_payload, + ATTR_ENTITY_ID: queued_event.entity_id, "calendar_event": queued_event.event.as_dict(), } self._action_runner(payload, "calendar event state change") @@ -260,8 +295,77 @@ class CalendarEventListener: self._listen_next_calendar_event() -class EventTrigger(Trigger): - """Calendar event trigger.""" +class TargetCalendarEventListener(TargetEntityChangeTracker): + """Helper class to listen to calendar events for target entity changes.""" + + def __init__( + self, + hass: HomeAssistant, + target_selection: TargetSelection, + event_type: str, + offset: datetime.timedelta, + run_action: TriggerActionRunner, + ) -> None: + """Initialize the state change tracker.""" + + def entity_filter(entities: set[str]) -> set[str]: + return { + entity_id + for entity_id in entities + if split_entity_id(entity_id)[0] == DOMAIN + } + + super().__init__(hass, target_selection, entity_filter) + self._event_type = event_type + self._offset = offset + self._run_action = run_action + self._trigger_data = { + "event": event_type, + "offset": offset, + } + + self._pending_listener_task: asyncio.Task[None] | None = None + self._calendar_event_listener: CalendarEventListener | None = None + + @callback + def _handle_entities_update(self, tracked_entities: set[str]) -> None: + """Restart the listeners when the list of entities of the tracked targets is updated.""" + if self._pending_listener_task: + self._pending_listener_task.cancel() + self._pending_listener_task = self._hass.async_create_task( + self._start_listening(tracked_entities) + ) + + async def _start_listening(self, tracked_entities: set[str]) -> None: + """Start listening for calendar events.""" + _LOGGER.debug("Tracking events for calendars: %s", tracked_entities) + if self._calendar_event_listener: + self._calendar_event_listener.async_detach() + self._calendar_event_listener = CalendarEventListener( + self._hass, + self._run_action, + self._trigger_data, + queued_event_fetcher( + event_fetcher(self._hass, tracked_entities), + self._event_type, + self._offset, + ), + ) + await self._calendar_event_listener.async_attach() + + def _unsubscribe(self) -> None: + """Unsubscribe from all events.""" + super()._unsubscribe() + if self._pending_listener_task: + self._pending_listener_task.cancel() + self._pending_listener_task = None + if self._calendar_event_listener: + self._calendar_event_listener.async_detach() + self._calendar_event_listener = None + + +class SingleEntityEventTrigger(Trigger): + """Legacy single calendar entity event trigger.""" _options: dict[str, Any] @@ -271,7 +375,7 @@ class EventTrigger(Trigger): ) -> ConfigType: """Validate complete config.""" complete_config = move_top_level_schema_fields_to_options( - complete_config, _OPTIONS_SCHEMA_DICT + complete_config, _SINGLE_ENTITY_EVENT_OPTIONS_SCHEMA ) return await super().async_validate_complete_config(hass, complete_config) @@ -280,7 +384,7 @@ class EventTrigger(Trigger): cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" - return cast(ConfigType, _CONFIG_SCHEMA(config)) + return cast(ConfigType, _SINGLE_ENTITY_EVENT_TRIGGER_SCHEMA(config)) def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None: """Initialize trigger.""" @@ -311,15 +415,72 @@ class EventTrigger(Trigger): run_action, trigger_data, queued_event_fetcher( - event_fetcher(self._hass, entity_id), event_type, offset + event_fetcher(self._hass, {entity_id}), event_type, offset ), ) await listener.async_attach() return listener.async_detach +class EventTrigger(Trigger): + """Calendar event trigger.""" + + _options: dict[str, Any] + _event_type: str + + @classmethod + async def async_validate_config( + cls, hass: HomeAssistant, config: ConfigType + ) -> ConfigType: + """Validate config.""" + return cast(ConfigType, _EVENT_TRIGGER_SCHEMA(config)) + + def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None: + """Initialize trigger.""" + super().__init__(hass, config) + + if TYPE_CHECKING: + assert config.target is not None + assert config.options is not None + self._target = config.target + self._options = config.options + + async def async_attach_runner( + self, run_action: TriggerActionRunner + ) -> CALLBACK_TYPE: + """Attach a trigger.""" + + offset = self._options[CONF_OFFSET] + offset_type = self._options[CONF_OFFSET_TYPE] + + if offset_type == OFFSET_TYPE_BEFORE: + offset = -offset + + target_selection = TargetSelection(self._target) + if not target_selection.has_any_target: + raise HomeAssistantError(f"No target defined in {self._target}") + listener = TargetCalendarEventListener( + self._hass, target_selection, self._event_type, offset, run_action + ) + return listener.async_setup() + + +class EventStartedTrigger(EventTrigger): + """Calendar event started trigger.""" + + _event_type = EVENT_START + + +class EventEndedTrigger(EventTrigger): + """Calendar event ended trigger.""" + + _event_type = EVENT_END + + TRIGGERS: dict[str, type[Trigger]] = { - "_": EventTrigger, + "_": SingleEntityEventTrigger, + "event_started": EventStartedTrigger, + "event_ended": EventEndedTrigger, } diff --git a/homeassistant/components/calendar/triggers.yaml b/homeassistant/components/calendar/triggers.yaml new file mode 100644 index 00000000000..37599b4515a --- /dev/null +++ b/homeassistant/components/calendar/triggers.yaml @@ -0,0 +1,27 @@ +.trigger_common: &trigger_common + target: + entity: + domain: calendar + fields: + offset: + required: true + default: + days: 0 + hours: 0 + minutes: 0 + seconds: 0 + selector: + duration: + enable_day: true + offset_type: + required: true + default: before + selector: + select: + translation_key: trigger_offset_type + options: + - before + - after + +event_started: *trigger_common +event_ended: *trigger_common diff --git a/homeassistant/components/cisco_webex_teams/notify.py b/homeassistant/components/cisco_webex_teams/notify.py index 2f76ed8f65a..888af58b798 100644 --- a/homeassistant/components/cisco_webex_teams/notify.py +++ b/homeassistant/components/cisco_webex_teams/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import voluptuous as vol from webexpythonsdk import ApiError, WebexAPI, exceptions @@ -51,7 +52,7 @@ class CiscoWebexNotificationService(BaseNotificationService): self.room = room self.client = client - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" title = "" diff --git a/homeassistant/components/clicksend_tts/notify.py b/homeassistant/components/clicksend_tts/notify.py index 5a08ccd7988..632b76bc7be 100644 --- a/homeassistant/components/clicksend_tts/notify.py +++ b/homeassistant/components/clicksend_tts/notify.py @@ -5,6 +5,7 @@ from __future__ import annotations from http import HTTPStatus import json import logging +from typing import Any import requests import voluptuous as vol @@ -81,7 +82,7 @@ class ClicksendNotificationService(BaseNotificationService): self.language = config[CONF_LANGUAGE] self.voice = config[CONF_VOICE] - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a voice call to a user.""" data = { "messages": [ diff --git a/homeassistant/components/cloud/__init__.py b/homeassistant/components/cloud/__init__.py index 410029c2716..17a1ad4800d 100644 --- a/homeassistant/components/cloud/__init__.py +++ b/homeassistant/components/cloud/__init__.py @@ -50,7 +50,6 @@ from . import ( from .client import CloudClient from .const import ( CONF_ACCOUNT_LINK_SERVER, - CONF_ACCOUNTS_SERVER, CONF_ACME_SERVER, CONF_ALEXA, CONF_ALIASES, @@ -138,7 +137,6 @@ _BASE_CONFIG_SCHEMA = vol.Schema( vol.Optional(CONF_ALEXA): ALEXA_SCHEMA, vol.Optional(CONF_GOOGLE_ACTIONS): GACTIONS_SCHEMA, vol.Optional(CONF_ACCOUNT_LINK_SERVER): str, - vol.Optional(CONF_ACCOUNTS_SERVER): str, vol.Optional(CONF_ACME_SERVER): str, vol.Optional(CONF_API_SERVER): str, vol.Optional(CONF_RELAYER_SERVER): str, diff --git a/homeassistant/components/cloud/const.py b/homeassistant/components/cloud/const.py index 2922d62792e..f69533aabe4 100644 --- a/homeassistant/components/cloud/const.py +++ b/homeassistant/components/cloud/const.py @@ -76,7 +76,6 @@ CONF_GOOGLE_ACTIONS = "google_actions" CONF_USER_POOL_ID = "user_pool_id" CONF_ACCOUNT_LINK_SERVER = "account_link_server" -CONF_ACCOUNTS_SERVER = "accounts_server" CONF_ACME_SERVER = "acme_server" CONF_API_SERVER = "api_server" CONF_DISCOVERY_SERVICE_ACTIONS = "discovery_service_actions" diff --git a/homeassistant/components/cloud/manifest.json b/homeassistant/components/cloud/manifest.json index bcf2d015808..1b8766b83df 100644 --- a/homeassistant/components/cloud/manifest.json +++ b/homeassistant/components/cloud/manifest.json @@ -13,6 +13,6 @@ "integration_type": "system", "iot_class": "cloud_push", "loggers": ["acme", "hass_nabucasa", "snitun"], - "requirements": ["hass-nabucasa==1.7.0"], + "requirements": ["hass-nabucasa==1.11.0"], "single_config_entry": true } diff --git a/homeassistant/components/compit/manifest.json b/homeassistant/components/compit/manifest.json index 8c32dcc8e45..256ce7b81c6 100644 --- a/homeassistant/components/compit/manifest.json +++ b/homeassistant/components/compit/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["compit"], "quality_scale": "bronze", - "requirements": ["compit-inext-api==0.3.4"] + "requirements": ["compit-inext-api==0.4.2"] } diff --git a/homeassistant/components/concord232/alarm_control_panel.py b/homeassistant/components/concord232/alarm_control_panel.py index 61cf2aebb31..f4498c43ab6 100644 --- a/homeassistant/components/concord232/alarm_control_panel.py +++ b/homeassistant/components/concord232/alarm_control_panel.py @@ -49,11 +49,11 @@ def setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the Concord232 alarm control panel platform.""" - name = config[CONF_NAME] - code = config.get(CONF_CODE) - mode = config[CONF_MODE] - host = config[CONF_HOST] - port = config[CONF_PORT] + name: str = config[CONF_NAME] + code: str | None = config.get(CONF_CODE) + mode: str = config[CONF_MODE] + host: str = config[CONF_HOST] + port: int = config[CONF_PORT] url = f"http://{host}:{port}" @@ -72,7 +72,7 @@ class Concord232Alarm(AlarmControlPanelEntity): | AlarmControlPanelEntityFeature.ARM_AWAY ) - def __init__(self, url, name, code, mode): + def __init__(self, url: str, name: str, code: str | None, mode: str) -> None: """Initialize the Concord232 alarm panel.""" self._attr_name = name @@ -125,7 +125,7 @@ class Concord232Alarm(AlarmControlPanelEntity): return self._alarm.arm("away") - def _validate_code(self, code, state): + def _validate_code(self, code: str | None, state: AlarmControlPanelState) -> bool: """Validate given code.""" if self._code is None: return True diff --git a/homeassistant/components/concord232/binary_sensor.py b/homeassistant/components/concord232/binary_sensor.py index a60cf31a646..cc4d3bb92bd 100644 --- a/homeassistant/components/concord232/binary_sensor.py +++ b/homeassistant/components/concord232/binary_sensor.py @@ -4,6 +4,7 @@ from __future__ import annotations import datetime import logging +from typing import Any from concord232 import client as concord232_client import requests @@ -29,8 +30,7 @@ CONF_ZONE_TYPES = "zone_types" DEFAULT_HOST = "localhost" DEFAULT_NAME = "Alarm" -DEFAULT_PORT = "5007" -DEFAULT_SSL = False +DEFAULT_PORT = 5007 SCAN_INTERVAL = datetime.timedelta(seconds=10) @@ -56,10 +56,10 @@ def setup_platform( ) -> None: """Set up the Concord232 binary sensor platform.""" - host = config[CONF_HOST] - port = config[CONF_PORT] - exclude = config[CONF_EXCLUDE_ZONES] - zone_types = config[CONF_ZONE_TYPES] + host: str = config[CONF_HOST] + port: int = config[CONF_PORT] + exclude: list[int] = config[CONF_EXCLUDE_ZONES] + zone_types: dict[int, BinarySensorDeviceClass] = config[CONF_ZONE_TYPES] sensors = [] try: @@ -84,7 +84,6 @@ def setup_platform( if zone["number"] not in exclude: sensors.append( Concord232ZoneSensor( - hass, client, zone, zone_types.get(zone["number"], get_opening_type(zone)), @@ -110,26 +109,25 @@ def get_opening_type(zone): class Concord232ZoneSensor(BinarySensorEntity): """Representation of a Concord232 zone as a sensor.""" - def __init__(self, hass, client, zone, zone_type): + def __init__( + self, + client: concord232_client.Client, + zone: dict[str, Any], + zone_type: BinarySensorDeviceClass, + ) -> None: """Initialize the Concord232 binary sensor.""" - self._hass = hass self._client = client self._zone = zone self._number = zone["number"] - self._zone_type = zone_type + self._attr_device_class = zone_type @property - def device_class(self): - """Return the class of this sensor, from DEVICE_CLASSES.""" - return self._zone_type - - @property - def name(self): + def name(self) -> str: """Return the name of the binary sensor.""" return self._zone["name"] @property - def is_on(self): + def is_on(self) -> bool: """Return true if the binary sensor is on.""" # True means "faulted" or "open" or "abnormal state" return bool(self._zone["state"] != "Normal") @@ -145,5 +143,5 @@ class Concord232ZoneSensor(BinarySensorEntity): if hasattr(self._client, "zones"): self._zone = next( - (x for x in self._client.zones if x["number"] == self._number), None + x for x in self._client.zones if x["number"] == self._number ) diff --git a/homeassistant/components/config/entity_registry.py b/homeassistant/components/config/entity_registry.py index a1ce5645d6b..3a593906bcd 100644 --- a/homeassistant/components/config/entity_registry.py +++ b/homeassistant/components/config/entity_registry.py @@ -11,13 +11,11 @@ from homeassistant import config_entries from homeassistant.components import websocket_api from homeassistant.components.websocket_api import ERR_NOT_FOUND, require_admin from homeassistant.core import HomeAssistant, callback -from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import ( config_validation as cv, device_registry as dr, entity_registry as er, ) -from homeassistant.helpers.entity_component import async_get_entity_suggested_object_id from homeassistant.helpers.json import json_dumps _LOGGER = logging.getLogger(__name__) @@ -351,26 +349,12 @@ def websocket_get_automatic_entity_ids( if not (entry := registry.entities.get(entity_id)): automatic_entity_ids[entity_id] = None continue - try: - suggested = async_get_entity_suggested_object_id(hass, entity_id) - except HomeAssistantError as err: - # This is raised if the entity has no object. - _LOGGER.debug( - "Unable to get suggested object ID for %s, entity ID: %s (%s)", - entry.entity_id, - entity_id, - err, - ) - automatic_entity_ids[entity_id] = None - continue - suggested_entity_id = registry.async_generate_entity_id( - entry.domain, - suggested or f"{entry.platform}_{entry.unique_id}", - current_entity_id=entity_id, + new_entity_id = registry.async_regenerate_entity_id( + entry, reserved_entity_ids=reserved_entity_ids, ) - automatic_entity_ids[entity_id] = suggested_entity_id - reserved_entity_ids.add(suggested_entity_id) + automatic_entity_ids[entity_id] = new_entity_id + reserved_entity_ids.add(new_entity_id) connection.send_message( websocket_api.result_message(msg["id"], automatic_entity_ids) diff --git a/homeassistant/components/datadog/manifest.json b/homeassistant/components/datadog/manifest.json index 3d0e4cf8e8a..2fac380007f 100644 --- a/homeassistant/components/datadog/manifest.json +++ b/homeassistant/components/datadog/manifest.json @@ -7,6 +7,5 @@ "integration_type": "service", "iot_class": "local_push", "loggers": ["datadog"], - "quality_scale": "legacy", "requirements": ["datadog==0.52.0"] } diff --git a/homeassistant/components/deconz/const.py b/homeassistant/components/deconz/const.py index 873f5cde284..6edc9beaf38 100644 --- a/homeassistant/components/deconz/const.py +++ b/homeassistant/components/deconz/const.py @@ -10,7 +10,7 @@ LOGGER = logging.getLogger(__package__) DOMAIN = "deconz" -HASSIO_CONFIGURATION_URL = "homeassistant://hassio/ingress/core_deconz" +HASSIO_CONFIGURATION_URL = "homeassistant://app/core_deconz" CONF_BRIDGE_ID = "bridgeid" CONF_GROUP_ID_BASE = "group_id_base" diff --git a/homeassistant/components/deconz/device_trigger.py b/homeassistant/components/deconz/device_trigger.py index 158ac391b9b..4bc723abfce 100644 --- a/homeassistant/components/deconz/device_trigger.py +++ b/homeassistant/components/deconz/device_trigger.py @@ -169,6 +169,7 @@ FRIENDS_OF_HUE_SWITCH = { } RODRET_REMOTE_MODEL = "RODRET Dimmer" +RODRET_REMOTE_MODEL_2 = "RODRET wireless dimmer" RODRET_REMOTE = { (CONF_SHORT_RELEASE, CONF_TURN_ON): {CONF_EVENT: 1002}, (CONF_LONG_PRESS, CONF_TURN_ON): {CONF_EVENT: 1001}, @@ -624,6 +625,7 @@ REMOTES = { HUE_WALL_REMOTE_MODEL: HUE_WALL_REMOTE, FRIENDS_OF_HUE_SWITCH_MODEL: FRIENDS_OF_HUE_SWITCH, RODRET_REMOTE_MODEL: RODRET_REMOTE, + RODRET_REMOTE_MODEL_2: RODRET_REMOTE, SOMRIG_REMOTE_MODEL: SOMRIG_REMOTE, STYRBAR_REMOTE_MODEL: STYRBAR_REMOTE, SYMFONISK_SOUND_CONTROLLER_MODEL: SYMFONISK_SOUND_CONTROLLER, diff --git a/homeassistant/components/digital_ocean/__init__.py b/homeassistant/components/digital_ocean/__init__.py index 306ddc8e9a5..b4bd6ab1b92 100644 --- a/homeassistant/components/digital_ocean/__init__.py +++ b/homeassistant/components/digital_ocean/__init__.py @@ -1,6 +1,7 @@ """Support for Digital Ocean.""" -from datetime import timedelta +from __future__ import annotations + import logging import digitalocean @@ -12,27 +13,12 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.typing import ConfigType from homeassistant.util import Throttle +from .const import DATA_DIGITAL_OCEAN, DOMAIN, MIN_TIME_BETWEEN_UPDATES + _LOGGER = logging.getLogger(__name__) -ATTR_CREATED_AT = "created_at" -ATTR_DROPLET_ID = "droplet_id" -ATTR_DROPLET_NAME = "droplet_name" -ATTR_FEATURES = "features" -ATTR_IPV4_ADDRESS = "ipv4_address" -ATTR_IPV6_ADDRESS = "ipv6_address" -ATTR_MEMORY = "memory" -ATTR_REGION = "region" -ATTR_VCPUS = "vcpus" -ATTRIBUTION = "Data provided by Digital Ocean" - -CONF_DROPLETS = "droplets" - -DATA_DIGITAL_OCEAN = "data_do" DIGITAL_OCEAN_PLATFORMS = [Platform.SWITCH, Platform.BINARY_SENSOR] -DOMAIN = "digital_ocean" - -MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) CONFIG_SCHEMA = vol.Schema( {DOMAIN: vol.Schema({vol.Required(CONF_ACCESS_TOKEN): cv.string})}, diff --git a/homeassistant/components/digital_ocean/binary_sensor.py b/homeassistant/components/digital_ocean/binary_sensor.py index f0bb6eba049..6439a97ade8 100644 --- a/homeassistant/components/digital_ocean/binary_sensor.py +++ b/homeassistant/components/digital_ocean/binary_sensor.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import voluptuous as vol @@ -16,7 +17,7 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import ( +from .const import ( ATTR_CREATED_AT, ATTR_DROPLET_ID, ATTR_DROPLET_NAME, @@ -65,6 +66,7 @@ class DigitalOceanBinarySensor(BinarySensorEntity): """Representation of a Digital Ocean droplet sensor.""" _attr_attribution = ATTRIBUTION + _attr_device_class = BinarySensorDeviceClass.MOVING def __init__(self, do, droplet_id): """Initialize a new Digital Ocean sensor.""" @@ -79,17 +81,12 @@ class DigitalOceanBinarySensor(BinarySensorEntity): return self.data.name @property - def is_on(self): + def is_on(self) -> bool: """Return true if the binary sensor is on.""" return self.data.status == "active" @property - def device_class(self): - """Return the class of this sensor.""" - return BinarySensorDeviceClass.MOVING - - @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes of the Digital Ocean droplet.""" return { ATTR_CREATED_AT: self.data.created_at, diff --git a/homeassistant/components/digital_ocean/const.py b/homeassistant/components/digital_ocean/const.py new file mode 100644 index 00000000000..77dfb1bf4e2 --- /dev/null +++ b/homeassistant/components/digital_ocean/const.py @@ -0,0 +1,30 @@ +"""Support for Digital Ocean.""" + +from __future__ import annotations + +from datetime import timedelta +from typing import TYPE_CHECKING + +from homeassistant.util.hass_dict import HassKey + +if TYPE_CHECKING: + from . import DigitalOcean + +ATTR_CREATED_AT = "created_at" +ATTR_DROPLET_ID = "droplet_id" +ATTR_DROPLET_NAME = "droplet_name" +ATTR_FEATURES = "features" +ATTR_IPV4_ADDRESS = "ipv4_address" +ATTR_IPV6_ADDRESS = "ipv6_address" +ATTR_MEMORY = "memory" +ATTR_REGION = "region" +ATTR_VCPUS = "vcpus" + +ATTRIBUTION = "Data provided by Digital Ocean" + +CONF_DROPLETS = "droplets" + +DOMAIN = "digital_ocean" +DATA_DIGITAL_OCEAN: HassKey[DigitalOcean] = HassKey(DOMAIN) + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) diff --git a/homeassistant/components/digital_ocean/switch.py b/homeassistant/components/digital_ocean/switch.py index 409fa63c1c2..a3e6b4f95bf 100644 --- a/homeassistant/components/digital_ocean/switch.py +++ b/homeassistant/components/digital_ocean/switch.py @@ -16,7 +16,7 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import ( +from .const import ( ATTR_CREATED_AT, ATTR_DROPLET_ID, ATTR_DROPLET_NAME, @@ -80,12 +80,12 @@ class DigitalOceanSwitch(SwitchEntity): return self.data.name @property - def is_on(self): + def is_on(self) -> bool: """Return true if switch is on.""" return self.data.status == "active" @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes of the Digital Ocean droplet.""" return { ATTR_CREATED_AT: self.data.created_at, diff --git a/homeassistant/components/dnsip/manifest.json b/homeassistant/components/dnsip/manifest.json index f014cbdbe88..d700c89ab6f 100644 --- a/homeassistant/components/dnsip/manifest.json +++ b/homeassistant/components/dnsip/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/dnsip", "integration_type": "service", "iot_class": "cloud_polling", - "requirements": ["aiodns==3.6.1"] + "requirements": ["aiodns==4.0.0"] } diff --git a/homeassistant/components/dovado/notify.py b/homeassistant/components/dovado/notify.py index 0b74f97d06f..b074b4cc17c 100644 --- a/homeassistant/components/dovado/notify.py +++ b/homeassistant/components/dovado/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any from homeassistant.components.notify import ATTR_TARGET, BaseNotificationService from homeassistant.core import HomeAssistant @@ -29,7 +30,7 @@ class DovadoSMSNotificationService(BaseNotificationService): """Initialize the service.""" self._client = client - def send_message(self, message, **kwargs): + def send_message(self, message: str, **kwargs: Any) -> None: """Send SMS to the specified target phone number.""" if not (target := kwargs.get(ATTR_TARGET)): _LOGGER.error("One target is required") diff --git a/homeassistant/components/easyenergy/manifest.json b/homeassistant/components/easyenergy/manifest.json index 5cecb1d49f6..c987e75e718 100644 --- a/homeassistant/components/easyenergy/manifest.json +++ b/homeassistant/components/easyenergy/manifest.json @@ -6,6 +6,6 @@ "documentation": "https://www.home-assistant.io/integrations/easyenergy", "integration_type": "service", "iot_class": "cloud_polling", - "requirements": ["easyenergy==2.1.2"], + "requirements": ["easyenergy==2.2.0"], "single_config_entry": true } diff --git a/homeassistant/components/ebusd/__init__.py b/homeassistant/components/ebusd/__init__.py index 5c36c311bff..a32993af094 100644 --- a/homeassistant/components/ebusd/__init__.py +++ b/homeassistant/components/ebusd/__init__.py @@ -1,6 +1,7 @@ """Support for Ebusd daemon for communication with eBUS heating systems.""" import logging +from typing import Any import ebusdpy import voluptuous as vol @@ -17,7 +18,7 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.typing import ConfigType -from .const import DOMAIN, SENSOR_TYPES +from .const import DOMAIN, EBUSD_DATA, SENSOR_TYPES _LOGGER = logging.getLogger(__name__) @@ -28,9 +29,9 @@ CACHE_TTL = 900 SERVICE_EBUSD_WRITE = "ebusd_write" -def verify_ebusd_config(config): +def verify_ebusd_config(config: ConfigType) -> ConfigType: """Verify eBusd config.""" - circuit = config[CONF_CIRCUIT] + circuit: str = config[CONF_CIRCUIT] for condition in config[CONF_MONITORED_CONDITIONS]: if condition not in SENSOR_TYPES[circuit]: raise vol.Invalid(f"Condition '{condition}' not in '{circuit}'.") @@ -59,17 +60,17 @@ CONFIG_SCHEMA = vol.Schema( def setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the eBusd component.""" _LOGGER.debug("Integration setup started") - conf = config[DOMAIN] - name = conf[CONF_NAME] - circuit = conf[CONF_CIRCUIT] - monitored_conditions = conf.get(CONF_MONITORED_CONDITIONS) - server_address = (conf.get(CONF_HOST), conf.get(CONF_PORT)) + conf: ConfigType = config[DOMAIN] + name: str = conf[CONF_NAME] + circuit: str = conf[CONF_CIRCUIT] + monitored_conditions: list[str] = conf[CONF_MONITORED_CONDITIONS] + server_address: tuple[str, int] = (conf[CONF_HOST], conf[CONF_PORT]) try: ebusdpy.init(server_address) except (TimeoutError, OSError): return False - hass.data[DOMAIN] = EbusdData(server_address, circuit) + hass.data[EBUSD_DATA] = EbusdData(server_address, circuit) sensor_config = { CONF_MONITORED_CONDITIONS: monitored_conditions, "client_name": name, @@ -77,7 +78,7 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: } load_platform(hass, Platform.SENSOR, DOMAIN, sensor_config, config) - hass.services.register(DOMAIN, SERVICE_EBUSD_WRITE, hass.data[DOMAIN].write) + hass.services.register(DOMAIN, SERVICE_EBUSD_WRITE, hass.data[EBUSD_DATA].write) _LOGGER.debug("Ebusd integration setup completed") return True @@ -86,13 +87,13 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: class EbusdData: """Get the latest data from Ebusd.""" - def __init__(self, address, circuit): + def __init__(self, address: tuple[str, int], circuit: str) -> None: """Initialize the data object.""" self._circuit = circuit self._address = address - self.value = {} + self.value: dict[str, Any] = {} - def update(self, name, stype): + def update(self, name: str, stype: int) -> None: """Call the Ebusd API to update the data.""" try: _LOGGER.debug("Opening socket to ebusd %s", name) diff --git a/homeassistant/components/ebusd/const.py b/homeassistant/components/ebusd/const.py index 4fb3032e19b..10e46f6a2b9 100644 --- a/homeassistant/components/ebusd/const.py +++ b/homeassistant/components/ebusd/const.py @@ -1,5 +1,9 @@ """Constants for ebus component.""" +from __future__ import annotations + +from typing import TYPE_CHECKING + from homeassistant.components.sensor import SensorDeviceClass from homeassistant.const import ( PERCENTAGE, @@ -8,277 +12,283 @@ from homeassistant.const import ( UnitOfTemperature, UnitOfTime, ) +from homeassistant.util.hass_dict import HassKey + +if TYPE_CHECKING: + from . import EbusdData DOMAIN = "ebusd" +EBUSD_DATA: HassKey[EbusdData] = HassKey(DOMAIN) # SensorTypes from ebusdpy module : # 0='decimal', 1='time-schedule', 2='switch', 3='string', 4='value;status' -SENSOR_TYPES = { +type SensorSpecs = tuple[str, str | None, str | None, int, SensorDeviceClass | None] +SENSOR_TYPES: dict[str, dict[str, SensorSpecs]] = { "700": { - "ActualFlowTemperatureDesired": [ + "ActualFlowTemperatureDesired": ( "Hc1ActualFlowTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "MaxFlowTemperatureDesired": [ + ), + "MaxFlowTemperatureDesired": ( "Hc1MaxFlowTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "MinFlowTemperatureDesired": [ + ), + "MinFlowTemperatureDesired": ( "Hc1MinFlowTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "PumpStatus": ["Hc1PumpStatus", None, "mdi:toggle-switch", 2, None], - "HCSummerTemperatureLimit": [ + ), + "PumpStatus": ("Hc1PumpStatus", None, "mdi:toggle-switch", 2, None), + "HCSummerTemperatureLimit": ( "Hc1SummerTempLimit", UnitOfTemperature.CELSIUS, "mdi:weather-sunny", 0, SensorDeviceClass.TEMPERATURE, - ], - "HolidayTemperature": [ + ), + "HolidayTemperature": ( "HolidayTemp", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "HWTemperatureDesired": [ + ), + "HWTemperatureDesired": ( "HwcTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "HWActualTemperature": [ + ), + "HWActualTemperature": ( "HwcStorageTemp", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "HWTimerMonday": ["hwcTimer.Monday", None, "mdi:timer-outline", 1, None], - "HWTimerTuesday": ["hwcTimer.Tuesday", None, "mdi:timer-outline", 1, None], - "HWTimerWednesday": ["hwcTimer.Wednesday", None, "mdi:timer-outline", 1, None], - "HWTimerThursday": ["hwcTimer.Thursday", None, "mdi:timer-outline", 1, None], - "HWTimerFriday": ["hwcTimer.Friday", None, "mdi:timer-outline", 1, None], - "HWTimerSaturday": ["hwcTimer.Saturday", None, "mdi:timer-outline", 1, None], - "HWTimerSunday": ["hwcTimer.Sunday", None, "mdi:timer-outline", 1, None], - "HWOperativeMode": ["HwcOpMode", None, "mdi:math-compass", 3, None], - "WaterPressure": [ + ), + "HWTimerMonday": ("hwcTimer.Monday", None, "mdi:timer-outline", 1, None), + "HWTimerTuesday": ("hwcTimer.Tuesday", None, "mdi:timer-outline", 1, None), + "HWTimerWednesday": ("hwcTimer.Wednesday", None, "mdi:timer-outline", 1, None), + "HWTimerThursday": ("hwcTimer.Thursday", None, "mdi:timer-outline", 1, None), + "HWTimerFriday": ("hwcTimer.Friday", None, "mdi:timer-outline", 1, None), + "HWTimerSaturday": ("hwcTimer.Saturday", None, "mdi:timer-outline", 1, None), + "HWTimerSunday": ("hwcTimer.Sunday", None, "mdi:timer-outline", 1, None), + "HWOperativeMode": ("HwcOpMode", None, "mdi:math-compass", 3, None), + "WaterPressure": ( "WaterPressure", UnitOfPressure.BAR, "mdi:water-pump", 0, SensorDeviceClass.PRESSURE, - ], - "Zone1RoomZoneMapping": ["z1RoomZoneMapping", None, "mdi:label", 0, None], - "Zone1NightTemperature": [ + ), + "Zone1RoomZoneMapping": ("z1RoomZoneMapping", None, "mdi:label", 0, None), + "Zone1NightTemperature": ( "z1NightTemp", UnitOfTemperature.CELSIUS, "mdi:weather-night", 0, SensorDeviceClass.TEMPERATURE, - ], - "Zone1DayTemperature": [ + ), + "Zone1DayTemperature": ( "z1DayTemp", UnitOfTemperature.CELSIUS, "mdi:weather-sunny", 0, SensorDeviceClass.TEMPERATURE, - ], - "Zone1HolidayTemperature": [ + ), + "Zone1HolidayTemperature": ( "z1HolidayTemp", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "Zone1RoomTemperature": [ + ), + "Zone1RoomTemperature": ( "z1RoomTemp", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "Zone1ActualRoomTemperatureDesired": [ + ), + "Zone1ActualRoomTemperatureDesired": ( "z1ActualRoomTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "Zone1TimerMonday": ["z1Timer.Monday", None, "mdi:timer-outline", 1, None], - "Zone1TimerTuesday": ["z1Timer.Tuesday", None, "mdi:timer-outline", 1, None], - "Zone1TimerWednesday": [ + ), + "Zone1TimerMonday": ("z1Timer.Monday", None, "mdi:timer-outline", 1, None), + "Zone1TimerTuesday": ("z1Timer.Tuesday", None, "mdi:timer-outline", 1, None), + "Zone1TimerWednesday": ( "z1Timer.Wednesday", None, "mdi:timer-outline", 1, None, - ], - "Zone1TimerThursday": ["z1Timer.Thursday", None, "mdi:timer-outline", 1, None], - "Zone1TimerFriday": ["z1Timer.Friday", None, "mdi:timer-outline", 1, None], - "Zone1TimerSaturday": ["z1Timer.Saturday", None, "mdi:timer-outline", 1, None], - "Zone1TimerSunday": ["z1Timer.Sunday", None, "mdi:timer-outline", 1, None], - "Zone1OperativeMode": ["z1OpMode", None, "mdi:math-compass", 3, None], - "ContinuosHeating": [ + ), + "Zone1TimerThursday": ("z1Timer.Thursday", None, "mdi:timer-outline", 1, None), + "Zone1TimerFriday": ("z1Timer.Friday", None, "mdi:timer-outline", 1, None), + "Zone1TimerSaturday": ("z1Timer.Saturday", None, "mdi:timer-outline", 1, None), + "Zone1TimerSunday": ("z1Timer.Sunday", None, "mdi:timer-outline", 1, None), + "Zone1OperativeMode": ("z1OpMode", None, "mdi:math-compass", 3, None), + "ContinuosHeating": ( "ContinuosHeating", UnitOfTemperature.CELSIUS, "mdi:weather-snowy", 0, SensorDeviceClass.TEMPERATURE, - ], - "PowerEnergyConsumptionLastMonth": [ + ), + "PowerEnergyConsumptionLastMonth": ( "PrEnergySumHcLastMonth", UnitOfEnergy.KILO_WATT_HOUR, "mdi:flash", 0, SensorDeviceClass.ENERGY, - ], - "PowerEnergyConsumptionThisMonth": [ + ), + "PowerEnergyConsumptionThisMonth": ( "PrEnergySumHcThisMonth", UnitOfEnergy.KILO_WATT_HOUR, "mdi:flash", 0, SensorDeviceClass.ENERGY, - ], + ), }, "ehp": { - "HWTemperature": [ + "HWTemperature": ( "HwcTemp", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], - "OutsideTemp": [ + ), + "OutsideTemp": ( "OutsideTemp", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], + ), }, "bai": { - "HotWaterTemperature": [ + "HotWaterTemperature": ( "HwcTemp", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], - "StorageTemperature": [ + ), + "StorageTemperature": ( "StorageTemp", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], - "DesiredStorageTemperature": [ + ), + "DesiredStorageTemperature": ( "StorageTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "OutdoorsTemperature": [ + ), + "OutdoorsTemperature": ( "OutdoorstempSensor", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], - "WaterPressure": [ + ), + "WaterPressure": ( "WaterPressure", UnitOfPressure.BAR, "mdi:pipe", 4, SensorDeviceClass.PRESSURE, - ], - "AverageIgnitionTime": [ + ), + "AverageIgnitionTime": ( "averageIgnitiontime", UnitOfTime.SECONDS, "mdi:av-timer", 0, SensorDeviceClass.DURATION, - ], - "MaximumIgnitionTime": [ + ), + "MaximumIgnitionTime": ( "maxIgnitiontime", UnitOfTime.SECONDS, "mdi:av-timer", 0, SensorDeviceClass.DURATION, - ], - "MinimumIgnitionTime": [ + ), + "MinimumIgnitionTime": ( "minIgnitiontime", UnitOfTime.SECONDS, "mdi:av-timer", 0, SensorDeviceClass.DURATION, - ], - "ReturnTemperature": [ + ), + "ReturnTemperature": ( "ReturnTemp", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], - "CentralHeatingPump": ["WP", None, "mdi:toggle-switch", 2, None], - "HeatingSwitch": ["HeatingSwitch", None, "mdi:toggle-switch", 2, None], - "DesiredFlowTemperature": [ + ), + "CentralHeatingPump": ("WP", None, "mdi:toggle-switch", 2, None), + "HeatingSwitch": ("HeatingSwitch", None, "mdi:toggle-switch", 2, None), + "DesiredFlowTemperature": ( "FlowTempDesired", UnitOfTemperature.CELSIUS, None, 0, SensorDeviceClass.TEMPERATURE, - ], - "FlowTemperature": [ + ), + "FlowTemperature": ( "FlowTemp", UnitOfTemperature.CELSIUS, None, 4, SensorDeviceClass.TEMPERATURE, - ], - "Flame": ["Flame", None, "mdi:toggle-switch", 2, None], - "PowerEnergyConsumptionHeatingCircuit": [ + ), + "Flame": ("Flame", None, "mdi:toggle-switch", 2, None), + "PowerEnergyConsumptionHeatingCircuit": ( "PrEnergySumHc1", UnitOfEnergy.KILO_WATT_HOUR, "mdi:flash", 0, SensorDeviceClass.ENERGY, - ], - "PowerEnergyConsumptionHotWaterCircuit": [ + ), + "PowerEnergyConsumptionHotWaterCircuit": ( "PrEnergySumHwc1", UnitOfEnergy.KILO_WATT_HOUR, "mdi:flash", 0, SensorDeviceClass.ENERGY, - ], - "RoomThermostat": ["DCRoomthermostat", None, "mdi:toggle-switch", 2, None], - "HeatingPartLoad": [ + ), + "RoomThermostat": ("DCRoomthermostat", None, "mdi:toggle-switch", 2, None), + "HeatingPartLoad": ( "PartloadHcKW", UnitOfEnergy.KILO_WATT_HOUR, "mdi:flash", 0, SensorDeviceClass.ENERGY, - ], - "StateNumber": ["StateNumber", None, "mdi:fire", 3, None], - "ModulationPercentage": [ + ), + "StateNumber": ("StateNumber", None, "mdi:fire", 3, None), + "ModulationPercentage": ( "ModulationTempDesired", PERCENTAGE, "mdi:percent", 0, None, - ], + ), }, } diff --git a/homeassistant/components/ebusd/sensor.py b/homeassistant/components/ebusd/sensor.py index ccd04be585e..a69a0343220 100644 --- a/homeassistant/components/ebusd/sensor.py +++ b/homeassistant/components/ebusd/sensor.py @@ -4,14 +4,16 @@ from __future__ import annotations import datetime import logging +from typing import Any, cast -from homeassistant.components.sensor import SensorEntity +from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.util import Throttle, dt as dt_util -from .const import DOMAIN +from . import EbusdData +from .const import EBUSD_DATA, SensorSpecs TIME_FRAME1_BEGIN = "time_frame1_begin" TIME_FRAME1_END = "time_frame1_end" @@ -33,9 +35,9 @@ def setup_platform( """Set up the Ebus sensor.""" if not discovery_info: return - ebusd_api = hass.data[DOMAIN] - monitored_conditions = discovery_info["monitored_conditions"] - name = discovery_info["client_name"] + ebusd_api = hass.data[EBUSD_DATA] + monitored_conditions: list[str] = discovery_info["monitored_conditions"] + name: str = discovery_info["client_name"] add_entities( ( @@ -49,9 +51,8 @@ def setup_platform( class EbusdSensor(SensorEntity): """Ebusd component sensor methods definition.""" - def __init__(self, data, sensor, name): + def __init__(self, data: EbusdData, sensor: SensorSpecs, name: str) -> None: """Initialize the sensor.""" - self._state = None self._client_name = name ( self._name, @@ -63,20 +64,15 @@ class EbusdSensor(SensorEntity): self.data = data @property - def name(self): + def name(self) -> str: """Return the name of the sensor.""" return f"{self._client_name} {self._name}" @property - def native_value(self): - """Return the state of the sensor.""" - return self._state - - @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any] | None: """Return the device state attributes.""" - if self._type == 1 and self._state is not None: - schedule = { + if self._type == 1 and (native_value := self.native_value) is not None: + schedule: dict[str, str | None] = { TIME_FRAME1_BEGIN: None, TIME_FRAME1_END: None, TIME_FRAME2_BEGIN: None, @@ -84,7 +80,7 @@ class EbusdSensor(SensorEntity): TIME_FRAME3_BEGIN: None, TIME_FRAME3_END: None, } - time_frame = self._state.split(";") + time_frame = cast(str, native_value).split(";") for index, item in enumerate(sorted(schedule.items())): if index < len(time_frame): parsed = datetime.datetime.strptime(time_frame[index], "%H:%M") @@ -96,17 +92,17 @@ class EbusdSensor(SensorEntity): return None @property - def device_class(self): + def device_class(self) -> SensorDeviceClass | None: """Return the class of this device, from component DEVICE_CLASSES.""" return self._device_class @property - def icon(self): + def icon(self) -> str | None: """Icon to use in the frontend, if any.""" return self._icon @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str | None: """Return the unit of measurement.""" return self._unit_of_measurement @@ -118,6 +114,6 @@ class EbusdSensor(SensorEntity): if self._name not in self.data.value: return - self._state = self.data.value[self._name] + self._attr_native_value = self.data.value[self._name] except RuntimeError: _LOGGER.debug("EbusdData.update exception") diff --git a/homeassistant/components/egardia/__init__.py b/homeassistant/components/egardia/__init__.py index eb6b4cd49d8..dc94bb79a4e 100644 --- a/homeassistant/components/egardia/__init__.py +++ b/homeassistant/components/egardia/__init__.py @@ -18,6 +18,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, discovery from homeassistant.helpers.typing import ConfigType +from homeassistant.util.hass_dict import HassKey _LOGGER = logging.getLogger(__name__) @@ -35,7 +36,7 @@ DEFAULT_REPORT_SERVER_PORT = 52010 DEFAULT_VERSION = "GATE-01" DOMAIN = "egardia" -EGARDIA_DEVICE = "egardiadevice" +EGARDIA_DEVICE: HassKey[egardiadevice.EgardiaDevice] = HassKey(DOMAIN) EGARDIA_NAME = "egardianame" EGARDIA_REPORT_SERVER_CODES = "egardia_rs_codes" EGARDIA_REPORT_SERVER_ENABLED = "egardia_rs_enabled" diff --git a/homeassistant/components/egardia/alarm_control_panel.py b/homeassistant/components/egardia/alarm_control_panel.py index 5a18a23541a..9ebe8c1704e 100644 --- a/homeassistant/components/egardia/alarm_control_panel.py +++ b/homeassistant/components/egardia/alarm_control_panel.py @@ -4,6 +4,7 @@ from __future__ import annotations import logging +from pythonegardia.egardiadevice import EgardiaDevice import requests from homeassistant.components.alarm_control_panel import ( @@ -11,6 +12,7 @@ from homeassistant.components.alarm_control_panel import ( AlarmControlPanelEntityFeature, AlarmControlPanelState, ) +from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -47,10 +49,10 @@ def setup_platform( if discovery_info is None: return device = EgardiaAlarm( - discovery_info["name"], + discovery_info[CONF_NAME], hass.data[EGARDIA_DEVICE], discovery_info[CONF_REPORT_SERVER_ENABLED], - discovery_info.get(CONF_REPORT_SERVER_CODES), + discovery_info[CONF_REPORT_SERVER_CODES], discovery_info[CONF_REPORT_SERVER_PORT], ) @@ -67,8 +69,13 @@ class EgardiaAlarm(AlarmControlPanelEntity): ) def __init__( - self, name, egardiasystem, rs_enabled=False, rs_codes=None, rs_port=52010 - ): + self, + name: str, + egardiasystem: EgardiaDevice, + rs_enabled: bool, + rs_codes: dict[str, list[str]], + rs_port: int, + ) -> None: """Initialize the Egardia alarm.""" self._attr_name = name self._egardiasystem = egardiasystem @@ -85,9 +92,7 @@ class EgardiaAlarm(AlarmControlPanelEntity): @property def should_poll(self) -> bool: """Poll if no report server is enabled.""" - if not self._rs_enabled: - return True - return False + return not self._rs_enabled def handle_status_event(self, event): """Handle the Egardia system status event.""" diff --git a/homeassistant/components/egardia/binary_sensor.py b/homeassistant/components/egardia/binary_sensor.py index 53505f58d3b..9c778cdad5a 100644 --- a/homeassistant/components/egardia/binary_sensor.py +++ b/homeassistant/components/egardia/binary_sensor.py @@ -2,11 +2,12 @@ from __future__ import annotations +from pythonegardia.egardiadevice import EgardiaDevice + from homeassistant.components.binary_sensor import ( BinarySensorDeviceClass, BinarySensorEntity, ) -from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -51,30 +52,20 @@ async def async_setup_platform( class EgardiaBinarySensor(BinarySensorEntity): """Represents a sensor based on an Egardia sensor (IR, Door Contact).""" - def __init__(self, sensor_id, name, egardia_system, device_class): + def __init__( + self, + sensor_id: str, + name: str, + egardia_system: EgardiaDevice, + device_class: BinarySensorDeviceClass | None, + ) -> None: """Initialize the sensor device.""" self._id = sensor_id - self._name = name - self._state = None - self._device_class = device_class + self._attr_name = name + self._attr_device_class = device_class self._egardia_system = egardia_system def update(self) -> None: """Update the status.""" egardia_input = self._egardia_system.getsensorstate(self._id) - self._state = STATE_ON if egardia_input else STATE_OFF - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def is_on(self): - """Whether the device is switched on.""" - return self._state == STATE_ON - - @property - def device_class(self): - """Return the device class.""" - return self._device_class + self._attr_is_on = bool(egardia_input) diff --git a/homeassistant/components/enphase_envoy/manifest.json b/homeassistant/components/enphase_envoy/manifest.json index bebbbe004e9..abc8d4cdad2 100644 --- a/homeassistant/components/enphase_envoy/manifest.json +++ b/homeassistant/components/enphase_envoy/manifest.json @@ -8,7 +8,7 @@ "iot_class": "local_polling", "loggers": ["pyenphase"], "quality_scale": "platinum", - "requirements": ["pyenphase==2.4.2"], + "requirements": ["pyenphase==2.4.3"], "zeroconf": [ { "type": "_enphase-envoy._tcp.local." diff --git a/homeassistant/components/envisalink/__init__.py b/homeassistant/components/envisalink/__init__.py index 919704a6728..ee5468ddd81 100644 --- a/homeassistant/components/envisalink/__init__.py +++ b/homeassistant/components/envisalink/__init__.py @@ -18,12 +18,13 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.typing import ConfigType +from homeassistant.util.hass_dict import HassKey _LOGGER = logging.getLogger(__name__) DOMAIN = "envisalink" -DATA_EVL = "envisalink" +DATA_EVL: HassKey[EnvisalinkAlarmPanel] = HassKey(DOMAIN) CONF_EVL_KEEPALIVE = "keepalive_interval" CONF_EVL_PORT = "port" diff --git a/homeassistant/components/envisalink/alarm_control_panel.py b/homeassistant/components/envisalink/alarm_control_panel.py index 9d1b6d0d7a1..c1cee5198f2 100644 --- a/homeassistant/components/envisalink/alarm_control_panel.py +++ b/homeassistant/components/envisalink/alarm_control_panel.py @@ -3,7 +3,9 @@ from __future__ import annotations import logging +from typing import Any +from pyenvisalink import EnvisalinkAlarmPanel import voluptuous as vol from homeassistant.components.alarm_control_panel import ( @@ -22,6 +24,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import ( CONF_PANIC, CONF_PARTITIONNAME, + CONF_PARTITIONS, DATA_EVL, DOMAIN, PARTITION_SCHEMA, @@ -51,15 +54,14 @@ async def async_setup_platform( """Perform the setup for Envisalink alarm panels.""" if not discovery_info: return - configured_partitions = discovery_info["partitions"] - code = discovery_info[CONF_CODE] - panic_type = discovery_info[CONF_PANIC] + configured_partitions: dict[int, dict[str, Any]] = discovery_info[CONF_PARTITIONS] + code: str | None = discovery_info[CONF_CODE] + panic_type: str = discovery_info[CONF_PANIC] entities = [] - for part_num in configured_partitions: - entity_config_data = PARTITION_SCHEMA(configured_partitions[part_num]) + for part_num, part_config in configured_partitions.items(): + entity_config_data = PARTITION_SCHEMA(part_config) entity = EnvisalinkAlarm( - hass, part_num, entity_config_data[CONF_PARTITIONNAME], code, @@ -103,8 +105,14 @@ class EnvisalinkAlarm(EnvisalinkEntity, AlarmControlPanelEntity): ) def __init__( - self, hass, partition_number, alarm_name, code, panic_type, info, controller - ): + self, + partition_number: int, + alarm_name: str, + code: str | None, + panic_type: str, + info: dict[str, Any], + controller: EnvisalinkAlarmPanel, + ) -> None: """Initialize the alarm panel.""" self._partition_number = partition_number self._panic_type = panic_type diff --git a/homeassistant/components/envisalink/binary_sensor.py b/homeassistant/components/envisalink/binary_sensor.py index 6c4e2b528e9..aa91731216f 100644 --- a/homeassistant/components/envisalink/binary_sensor.py +++ b/homeassistant/components/envisalink/binary_sensor.py @@ -4,8 +4,14 @@ from __future__ import annotations import datetime import logging +from typing import Any -from homeassistant.components.binary_sensor import BinarySensorEntity +from pyenvisalink import EnvisalinkAlarmPanel + +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, +) from homeassistant.const import ATTR_LAST_TRIP_TIME from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -13,7 +19,14 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.util import dt as dt_util -from . import CONF_ZONENAME, CONF_ZONETYPE, DATA_EVL, SIGNAL_ZONE_UPDATE, ZONE_SCHEMA +from . import ( + CONF_ZONENAME, + CONF_ZONES, + CONF_ZONETYPE, + DATA_EVL, + SIGNAL_ZONE_UPDATE, + ZONE_SCHEMA, +) from .entity import EnvisalinkEntity _LOGGER = logging.getLogger(__name__) @@ -28,13 +41,12 @@ async def async_setup_platform( """Set up the Envisalink binary sensor entities.""" if not discovery_info: return - configured_zones = discovery_info["zones"] + configured_zones: dict[int, dict[str, Any]] = discovery_info[CONF_ZONES] entities = [] - for zone_num in configured_zones: - entity_config_data = ZONE_SCHEMA(configured_zones[zone_num]) + for zone_num, zone_data in configured_zones.items(): + entity_config_data = ZONE_SCHEMA(zone_data) entity = EnvisalinkBinarySensor( - hass, zone_num, entity_config_data[CONF_ZONENAME], entity_config_data[CONF_ZONETYPE], @@ -49,9 +61,16 @@ async def async_setup_platform( class EnvisalinkBinarySensor(EnvisalinkEntity, BinarySensorEntity): """Representation of an Envisalink binary sensor.""" - def __init__(self, hass, zone_number, zone_name, zone_type, info, controller): + def __init__( + self, + zone_number: int, + zone_name: str, + zone_type: BinarySensorDeviceClass, + info: dict[str, Any], + controller: EnvisalinkAlarmPanel, + ) -> None: """Initialize the binary_sensor.""" - self._zone_type = zone_type + self._attr_device_class = zone_type self._zone_number = zone_number _LOGGER.debug("Setting up zone: %s", zone_name) @@ -66,9 +85,9 @@ class EnvisalinkBinarySensor(EnvisalinkEntity, BinarySensorEntity): ) @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" - attr = {} + attr: dict[str, Any] = {} # The Envisalink library returns a "last_fault" value that's the # number of seconds since the last fault, up to a maximum of 327680 @@ -101,11 +120,6 @@ class EnvisalinkBinarySensor(EnvisalinkEntity, BinarySensorEntity): """Return true if sensor is on.""" return self._info["status"]["open"] - @property - def device_class(self): - """Return the class of this sensor, from DEVICE_CLASSES.""" - return self._zone_type - @callback def async_update_callback(self, zone): """Update the zone's state, if needed.""" diff --git a/homeassistant/components/envisalink/entity.py b/homeassistant/components/envisalink/entity.py index a686ed2e3cb..6327ecee4e9 100644 --- a/homeassistant/components/envisalink/entity.py +++ b/homeassistant/components/envisalink/entity.py @@ -1,5 +1,9 @@ """Support for Envisalink devices.""" +from typing import Any + +from pyenvisalink import EnvisalinkAlarmPanel + from homeassistant.helpers.entity import Entity @@ -8,13 +12,10 @@ class EnvisalinkEntity(Entity): _attr_should_poll = False - def __init__(self, name, info, controller): + def __init__( + self, name: str, info: dict[str, Any], controller: EnvisalinkAlarmPanel + ) -> None: """Initialize the device.""" self._controller = controller self._info = info - self._name = name - - @property - def name(self): - """Return the name of the device.""" - return self._name + self._attr_name = name diff --git a/homeassistant/components/envisalink/sensor.py b/homeassistant/components/envisalink/sensor.py index 70d471a685c..d9b9ccab164 100644 --- a/homeassistant/components/envisalink/sensor.py +++ b/homeassistant/components/envisalink/sensor.py @@ -3,6 +3,9 @@ from __future__ import annotations import logging +from typing import Any + +from pyenvisalink import EnvisalinkAlarmPanel from homeassistant.components.sensor import SensorEntity from homeassistant.core import HomeAssistant, callback @@ -12,6 +15,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from . import ( CONF_PARTITIONNAME, + CONF_PARTITIONS, DATA_EVL, PARTITION_SCHEMA, SIGNAL_KEYPAD_UPDATE, @@ -31,13 +35,12 @@ async def async_setup_platform( """Perform the setup for Envisalink sensor entities.""" if not discovery_info: return - configured_partitions = discovery_info["partitions"] + configured_partitions: dict[int, dict[str, Any]] = discovery_info[CONF_PARTITIONS] entities = [] - for part_num in configured_partitions: - entity_config_data = PARTITION_SCHEMA(configured_partitions[part_num]) + for part_num, part_config in configured_partitions.items(): + entity_config_data = PARTITION_SCHEMA(part_config) entity = EnvisalinkSensor( - hass, entity_config_data[CONF_PARTITIONNAME], part_num, hass.data[DATA_EVL].alarm_state["partition"][part_num], @@ -52,9 +55,16 @@ async def async_setup_platform( class EnvisalinkSensor(EnvisalinkEntity, SensorEntity): """Representation of an Envisalink keypad.""" - def __init__(self, hass, partition_name, partition_number, info, controller): + _attr_icon = "mdi:alarm" + + def __init__( + self, + partition_name: str, + partition_number: int, + info: dict[str, Any], + controller: EnvisalinkAlarmPanel, + ) -> None: """Initialize the sensor.""" - self._icon = "mdi:alarm" self._partition_number = partition_number _LOGGER.debug("Setting up sensor for partition: %s", partition_name) @@ -73,11 +83,6 @@ class EnvisalinkSensor(EnvisalinkEntity, SensorEntity): ) ) - @property - def icon(self): - """Return the icon if any.""" - return self._icon - @property def native_value(self): """Return the overall state.""" diff --git a/homeassistant/components/envisalink/switch.py b/homeassistant/components/envisalink/switch.py index e4f37bf328d..81ecf8d8789 100644 --- a/homeassistant/components/envisalink/switch.py +++ b/homeassistant/components/envisalink/switch.py @@ -5,13 +5,21 @@ from __future__ import annotations import logging from typing import Any +from pyenvisalink import EnvisalinkAlarmPanel + from homeassistant.components.switch import SwitchEntity from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import CONF_ZONENAME, DATA_EVL, SIGNAL_ZONE_BYPASS_UPDATE, ZONE_SCHEMA +from . import ( + CONF_ZONENAME, + CONF_ZONES, + DATA_EVL, + SIGNAL_ZONE_BYPASS_UPDATE, + ZONE_SCHEMA, +) from .entity import EnvisalinkEntity _LOGGER = logging.getLogger(__name__) @@ -26,16 +34,15 @@ async def async_setup_platform( """Set up the Envisalink switch entities.""" if not discovery_info: return - configured_zones = discovery_info["zones"] + configured_zones: dict[int, dict[str, Any]] = discovery_info[CONF_ZONES] entities = [] - for zone_num in configured_zones: - entity_config_data = ZONE_SCHEMA(configured_zones[zone_num]) + for zone_num, zone_data in configured_zones.items(): + entity_config_data = ZONE_SCHEMA(zone_data) zone_name = f"{entity_config_data[CONF_ZONENAME]}_bypass" _LOGGER.debug("Setting up zone_bypass switch: %s", zone_name) entity = EnvisalinkSwitch( - hass, zone_num, zone_name, hass.data[DATA_EVL].alarm_state["zone"][zone_num], @@ -49,7 +56,13 @@ async def async_setup_platform( class EnvisalinkSwitch(EnvisalinkEntity, SwitchEntity): """Representation of an Envisalink switch.""" - def __init__(self, hass, zone_number, zone_name, info, controller): + def __init__( + self, + zone_number: int, + zone_name: str, + info: dict[str, Any], + controller: EnvisalinkAlarmPanel, + ) -> None: """Initialize the switch.""" self._zone_number = zone_number diff --git a/homeassistant/components/esphome/manager.py b/homeassistant/components/esphome/manager.py index f0d1123cdcd..87b7ec3361e 100644 --- a/homeassistant/components/esphome/manager.py +++ b/homeassistant/components/esphome/manager.py @@ -1034,7 +1034,7 @@ def _async_setup_device_registry( and dashboard.data and dashboard.data.get(device_info.name) ): - configuration_url = f"homeassistant://hassio/ingress/{dashboard.addon_slug}" + configuration_url = f"homeassistant://app/{dashboard.addon_slug}" manufacturer = "espressif" if device_info.manufacturer: diff --git a/homeassistant/components/essent/const.py b/homeassistant/components/essent/const.py index 6b4167925c0..4b505e21136 100644 --- a/homeassistant/components/essent/const.py +++ b/homeassistant/components/essent/const.py @@ -7,7 +7,7 @@ from enum import StrEnum from typing import Final DOMAIN: Final = "essent" -UPDATE_INTERVAL: Final = timedelta(hours=12) +UPDATE_INTERVAL: Final = timedelta(hours=1) ATTRIBUTION: Final = "Data provided by Essent" diff --git a/homeassistant/components/facebook/notify.py b/homeassistant/components/facebook/notify.py index edd46d24982..674da78ead2 100644 --- a/homeassistant/components/facebook/notify.py +++ b/homeassistant/components/facebook/notify.py @@ -5,6 +5,7 @@ from __future__ import annotations from http import HTTPStatus import json import logging +from typing import Any import requests import voluptuous as vol @@ -46,7 +47,7 @@ class FacebookNotificationService(BaseNotificationService): """Initialize the service.""" self.page_access_token = access_token - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send some message.""" payload = {"access_token": self.page_access_token} targets = kwargs.get(ATTR_TARGET) diff --git a/homeassistant/components/fan/condition.py b/homeassistant/components/fan/condition.py new file mode 100644 index 00000000000..2063e98033e --- /dev/null +++ b/homeassistant/components/fan/condition.py @@ -0,0 +1,17 @@ +"""Provides conditions for fans.""" + +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant +from homeassistant.helpers.condition import Condition, make_entity_state_condition + +from . import DOMAIN + +CONDITIONS: dict[str, type[Condition]] = { + "is_off": make_entity_state_condition(DOMAIN, STATE_OFF), + "is_on": make_entity_state_condition(DOMAIN, STATE_ON), +} + + +async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]: + """Return the fan conditions.""" + return CONDITIONS diff --git a/homeassistant/components/fan/conditions.yaml b/homeassistant/components/fan/conditions.yaml new file mode 100644 index 00000000000..2f7e4fca5b9 --- /dev/null +++ b/homeassistant/components/fan/conditions.yaml @@ -0,0 +1,17 @@ +.condition_common: &condition_common + target: + entity: + domain: fan + fields: + behavior: + required: true + default: any + selector: + select: + translation_key: condition_behavior + options: + - all + - any + +is_off: *condition_common +is_on: *condition_common diff --git a/homeassistant/components/fan/icons.json b/homeassistant/components/fan/icons.json index 9f52b55bf7d..91a1924056f 100644 --- a/homeassistant/components/fan/icons.json +++ b/homeassistant/components/fan/icons.json @@ -1,4 +1,12 @@ { + "conditions": { + "is_off": { + "condition": "mdi:fan-off" + }, + "is_on": { + "condition": "mdi:fan" + } + }, "entity_component": { "_": { "default": "mdi:fan", diff --git a/homeassistant/components/fan/strings.json b/homeassistant/components/fan/strings.json index a6e4b91c65e..ba6df0a288f 100644 --- a/homeassistant/components/fan/strings.json +++ b/homeassistant/components/fan/strings.json @@ -1,8 +1,32 @@ { "common": { + "condition_behavior_description": "How the state should match on the targeted fans.", + "condition_behavior_name": "Behavior", "trigger_behavior_description": "The behavior of the targeted fans to trigger on.", "trigger_behavior_name": "Behavior" }, + "conditions": { + "is_off": { + "description": "Tests if one or more fans are off.", + "fields": { + "behavior": { + "description": "[%key:component::fan::common::condition_behavior_description%]", + "name": "[%key:component::fan::common::condition_behavior_name%]" + } + }, + "name": "If a fan is off" + }, + "is_on": { + "description": "Tests if one or more fans are on.", + "fields": { + "behavior": { + "description": "[%key:component::fan::common::condition_behavior_description%]", + "name": "[%key:component::fan::common::condition_behavior_name%]" + } + }, + "name": "If a fan is on" + } + }, "device_automation": { "action_type": { "toggle": "[%key:common::device_automation::action_type::toggle%]", @@ -65,6 +89,12 @@ } }, "selector": { + "condition_behavior": { + "options": { + "all": "All", + "any": "Any" + } + }, "direction": { "options": { "forward": "Forward", diff --git a/homeassistant/components/firefly_iii/coordinator.py b/homeassistant/components/firefly_iii/coordinator.py index 3ff2e326ebf..b5250d584d5 100644 --- a/homeassistant/components/firefly_iii/coordinator.py +++ b/homeassistant/components/firefly_iii/coordinator.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio from dataclasses import dataclass from datetime import datetime, timedelta import logging @@ -97,17 +98,30 @@ class FireflyDataUpdateCoordinator(DataUpdateCoordinator[FireflyCoordinatorData] end_date = now try: - accounts = await self.firefly.get_accounts() - categories = await self.firefly.get_categories() - category_details = [ - await self.firefly.get_category( - category_id=int(category.id), start=start_date, end=end_date + ( + accounts, + categories, + primary_currency, + budgets, + bills, + ) = await asyncio.gather( + self.firefly.get_accounts(), + self.firefly.get_categories(), + self.firefly.get_currency_primary(), + self.firefly.get_budgets(start=start_date, end=end_date), + self.firefly.get_bills(), + ) + + category_details = await asyncio.gather( + *( + self.firefly.get_category( + category_id=int(category.id), + start=start_date, + end=end_date, + ) + for category in categories ) - for category in categories - ] - primary_currency = await self.firefly.get_currency_primary() - budgets = await self.firefly.get_budgets(start=start_date, end=end_date) - bills = await self.firefly.get_bills() + ) except FireflyAuthenticationError as err: raise ConfigEntryAuthFailed( translation_domain=DOMAIN, diff --git a/homeassistant/components/firefly_iii/manifest.json b/homeassistant/components/firefly_iii/manifest.json index 81330d45215..7af55ca1fc4 100644 --- a/homeassistant/components/firefly_iii/manifest.json +++ b/homeassistant/components/firefly_iii/manifest.json @@ -7,5 +7,5 @@ "integration_type": "service", "iot_class": "local_polling", "quality_scale": "bronze", - "requirements": ["pyfirefly==0.1.10"] + "requirements": ["pyfirefly==0.1.12"] } diff --git a/homeassistant/components/fitbit/sensor.py b/homeassistant/components/fitbit/sensor.py index 9cee1d4f952..d8025225df5 100644 --- a/homeassistant/components/fitbit/sensor.py +++ b/homeassistant/components/fitbit/sensor.py @@ -461,7 +461,7 @@ FITBIT_RESOURCES_LIST: Final[tuple[FitbitSensorEntityDescription, ...]] = ( key="sleep/timeInBed", translation_key="sleep_time_in_bed", native_unit_of_measurement=UnitOfTime.MINUTES, - icon="mdi:hotel", + icon="mdi:bed", device_class=SensorDeviceClass.DURATION, scope=FitbitScope.SLEEP, state_class=SensorStateClass.TOTAL_INCREASING, diff --git a/homeassistant/components/flock/notify.py b/homeassistant/components/flock/notify.py index f50e04cba36..d4e8f864ee8 100644 --- a/homeassistant/components/flock/notify.py +++ b/homeassistant/components/flock/notify.py @@ -5,6 +5,7 @@ from __future__ import annotations import asyncio from http import HTTPStatus import logging +from typing import Any import voluptuous as vol @@ -47,7 +48,7 @@ class FlockNotificationService(BaseNotificationService): self._url = url self._session = session - async def async_send_message(self, message, **kwargs): + async def async_send_message(self, message: str, **kwargs: Any) -> None: """Send the message to the user.""" payload = {"text": message} diff --git a/homeassistant/components/free_mobile/notify.py b/homeassistant/components/free_mobile/notify.py index c7e3071c771..8f6613c5c23 100644 --- a/homeassistant/components/free_mobile/notify.py +++ b/homeassistant/components/free_mobile/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations from http import HTTPStatus import logging +from typing import Any from freesms import FreeClient import voluptuous as vol @@ -40,7 +41,7 @@ class FreeSMSNotificationService(BaseNotificationService): """Initialize the service.""" self.free_client = FreeClient(username, access_token) - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to the Free Mobile user cell.""" resp = self.free_client.send_sms(message) diff --git a/homeassistant/components/fressnapf_tracker/config_flow.py b/homeassistant/components/fressnapf_tracker/config_flow.py index 3823246308e..50531fe4624 100644 --- a/homeassistant/components/fressnapf_tracker/config_flow.py +++ b/homeassistant/components/fressnapf_tracker/config_flow.py @@ -31,7 +31,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema( ) STEP_SMS_CODE_DATA_SCHEMA = vol.Schema( { - vol.Required(CONF_SMS_CODE): int, + vol.Required(CONF_SMS_CODE): str, } ) @@ -75,7 +75,7 @@ class FressnapfTrackerConfigFlow(ConfigFlow, domain=DOMAIN): return errors, False async def _async_verify_sms_code( - self, sms_code: int + self, sms_code: str ) -> tuple[dict[str, str], str | None]: """Verify SMS code and return errors and access_token.""" errors: dict[str, str] = {} diff --git a/homeassistant/components/fressnapf_tracker/manifest.json b/homeassistant/components/fressnapf_tracker/manifest.json index 4e493db07e9..482db2aedb0 100644 --- a/homeassistant/components/fressnapf_tracker/manifest.json +++ b/homeassistant/components/fressnapf_tracker/manifest.json @@ -7,5 +7,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "quality_scale": "bronze", - "requirements": ["fressnapftracker==0.2.0"] + "requirements": ["fressnapftracker==0.2.1"] } diff --git a/homeassistant/components/fritz/button.py b/homeassistant/components/fritz/button.py index 7fd158f3224..af5c1b0e869 100644 --- a/homeassistant/components/fritz/button.py +++ b/homeassistant/components/fritz/button.py @@ -164,13 +164,12 @@ def _async_wol_buttons_list( class FritzBoxWOLButton(FritzDeviceBase, ButtonEntity): """Defines a FRITZ!Box Tools Wake On LAN button.""" - _attr_icon = "mdi:lan-pending" _attr_entity_registry_enabled_default = False + _attr_translation_key = "wake_on_lan" def __init__(self, avm_wrapper: AvmWrapper, device: FritzDevice) -> None: """Initialize Fritz!Box WOL button.""" super().__init__(avm_wrapper, device) - self._name = f"{self.hostname} Wake on LAN" self._attr_unique_id = f"{self._mac}_wake_on_lan" self._is_available = True diff --git a/homeassistant/components/fritz/device_tracker.py b/homeassistant/components/fritz/device_tracker.py index a658f5d19cb..aa3dcf1370a 100644 --- a/homeassistant/components/fritz/device_tracker.py +++ b/homeassistant/components/fritz/device_tracker.py @@ -10,6 +10,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from .const import DEFAULT_DEVICE_NAME from .coordinator import FRITZ_DATA_KEY, AvmWrapper, FritzConfigEntry, FritzData from .entity import FritzDeviceBase from .helpers import device_filter_out_from_trackers @@ -71,6 +72,7 @@ class FritzBoxTracker(FritzDeviceBase, ScannerEntity): def __init__(self, avm_wrapper: AvmWrapper, device: FritzDevice) -> None: """Initialize a FRITZ!Box device.""" super().__init__(avm_wrapper, device) + self._attr_name: str = device.hostname or DEFAULT_DEVICE_NAME self._last_activity: datetime.datetime | None = device.last_activity @property diff --git a/homeassistant/components/fritz/entity.py b/homeassistant/components/fritz/entity.py index eb3d5b600dd..ad2a4d831d0 100644 --- a/homeassistant/components/fritz/entity.py +++ b/homeassistant/components/fritz/entity.py @@ -13,7 +13,7 @@ from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DEFAULT_DEVICE_NAME, DOMAIN +from .const import DOMAIN from .coordinator import AvmWrapper from .models import FritzDevice @@ -21,21 +21,17 @@ from .models import FritzDevice class FritzDeviceBase(CoordinatorEntity[AvmWrapper]): """Entity base class for a device connected to a FRITZ!Box device.""" + _attr_has_entity_name = True + def __init__(self, avm_wrapper: AvmWrapper, device: FritzDevice) -> None: """Initialize a FRITZ!Box device.""" super().__init__(avm_wrapper) self._avm_wrapper = avm_wrapper self._mac: str = device.mac_address - self._name: str = device.hostname or DEFAULT_DEVICE_NAME self._attr_device_info = DeviceInfo( connections={(dr.CONNECTION_NETWORK_MAC, device.mac_address)} ) - @property - def name(self) -> str: - """Return device name.""" - return self._name - @property def ip_address(self) -> str | None: """Return the primary ip address of the device.""" diff --git a/homeassistant/components/fritz/icons.json b/homeassistant/components/fritz/icons.json index c20a8518b10..837c9b51095 100644 --- a/homeassistant/components/fritz/icons.json +++ b/homeassistant/components/fritz/icons.json @@ -3,6 +3,9 @@ "button": { "cleanup": { "default": "mdi:broom" + }, + "wake_on_lan": { + "default": "mdi:lan-pending" } }, "sensor": { @@ -48,6 +51,11 @@ "max_kb_s_sent": { "default": "mdi:upload" } + }, + "switch": { + "internet_access": { + "default": "mdi:router-wireless-settings" + } } }, "services": { diff --git a/homeassistant/components/fritz/manifest.json b/homeassistant/components/fritz/manifest.json index 45d9c6a0d5f..183bb931a14 100644 --- a/homeassistant/components/fritz/manifest.json +++ b/homeassistant/components/fritz/manifest.json @@ -8,6 +8,7 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["fritzconnection"], + "quality_scale": "bronze", "requirements": ["fritzconnection[qr]==1.15.0", "xmltodict==1.0.2"], "ssdp": [ { diff --git a/homeassistant/components/fritz/quality_scale.yaml b/homeassistant/components/fritz/quality_scale.yaml index c2d18a0be84..f1893ef317f 100644 --- a/homeassistant/components/fritz/quality_scale.yaml +++ b/homeassistant/components/fritz/quality_scale.yaml @@ -13,9 +13,7 @@ rules: docs-removal-instructions: done entity-event-setup: done entity-unique-id: done - has-entity-name: - status: todo - comment: partially done + has-entity-name: done runtime-data: done test-before-configure: done test-before-setup: done diff --git a/homeassistant/components/fritz/strings.json b/homeassistant/components/fritz/strings.json index baff078bc41..c2aa92818b1 100644 --- a/homeassistant/components/fritz/strings.json +++ b/homeassistant/components/fritz/strings.json @@ -108,6 +108,9 @@ }, "reconnect": { "name": "Reconnect" + }, + "wake_on_lan": { + "name": "Wake on LAN" } }, "sensor": { @@ -162,6 +165,11 @@ "max_kb_s_sent": { "name": "Max connection upload throughput" } + }, + "switch": { + "internet_access": { + "name": "Internet access" + } } }, "exceptions": { diff --git a/homeassistant/components/fritz/switch.py b/homeassistant/components/fritz/switch.py index 9c143ad9471..45afbb45eb8 100644 --- a/homeassistant/components/fritz/switch.py +++ b/homeassistant/components/fritz/switch.py @@ -499,13 +499,12 @@ class FritzBoxDeflectionSwitch(FritzBoxBaseCoordinatorSwitch): class FritzBoxProfileSwitch(FritzDeviceBase, SwitchEntity): """Defines a FRITZ!Box Tools DeviceProfile switch.""" - _attr_icon = "mdi:router-wireless-settings" + _attr_translation_key = "internet_access" def __init__(self, avm_wrapper: AvmWrapper, device: FritzDevice) -> None: """Init Fritz profile.""" super().__init__(avm_wrapper, device) self._attr_is_on: bool = False - self._name = f"{device.hostname} Internet Access" self._attr_unique_id = f"{self._mac}_internet_access" self._attr_entity_category = EntityCategory.CONFIG diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 17140d49ac9..cbbf414fbb3 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -23,5 +23,5 @@ "winter_mode": {} }, "quality_scale": "internal", - "requirements": ["home-assistant-frontend==20260107.0"] + "requirements": ["home-assistant-frontend==20260107.2"] } diff --git a/homeassistant/components/generic_thermostat/climate.py b/homeassistant/components/generic_thermostat/climate.py index 76fcc4acdde..26a368bcd66 100644 --- a/homeassistant/components/generic_thermostat/climate.py +++ b/homeassistant/components/generic_thermostat/climate.py @@ -66,6 +66,7 @@ from .const import ( CONF_COLD_TOLERANCE, CONF_HEATER, CONF_HOT_TOLERANCE, + CONF_KEEP_ALIVE, CONF_MAX_TEMP, CONF_MIN_DUR, CONF_MIN_TEMP, @@ -81,7 +82,6 @@ _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = "Generic Thermostat" CONF_INITIAL_HVAC_MODE = "initial_hvac_mode" -CONF_KEEP_ALIVE = "keep_alive" CONF_PRECISION = "precision" CONF_TARGET_TEMP = "target_temp" CONF_TEMP_STEP = "target_temp_step" diff --git a/homeassistant/components/generic_thermostat/config_flow.py b/homeassistant/components/generic_thermostat/config_flow.py index c1045cad536..88a09013d75 100644 --- a/homeassistant/components/generic_thermostat/config_flow.py +++ b/homeassistant/components/generic_thermostat/config_flow.py @@ -21,6 +21,7 @@ from .const import ( CONF_COLD_TOLERANCE, CONF_HEATER, CONF_HOT_TOLERANCE, + CONF_KEEP_ALIVE, CONF_MAX_TEMP, CONF_MIN_DUR, CONF_MIN_TEMP, @@ -59,6 +60,9 @@ OPTIONS_SCHEMA = { vol.Optional(CONF_MIN_DUR): selector.DurationSelector( selector.DurationSelectorConfig(allow_negative=False) ), + vol.Optional(CONF_KEEP_ALIVE): selector.DurationSelector( + selector.DurationSelectorConfig(allow_negative=False) + ), vol.Optional(CONF_MIN_TEMP): selector.NumberSelector( selector.NumberSelectorConfig( mode=selector.NumberSelectorMode.BOX, unit_of_measurement=DEGREE, step=0.1 diff --git a/homeassistant/components/generic_thermostat/const.py b/homeassistant/components/generic_thermostat/const.py index f0e6f1a7d73..d4c25f698d2 100644 --- a/homeassistant/components/generic_thermostat/const.py +++ b/homeassistant/components/generic_thermostat/const.py @@ -33,4 +33,5 @@ CONF_PRESETS = { ) } CONF_SENSOR = "target_sensor" +CONF_KEEP_ALIVE = "keep_alive" DEFAULT_TOLERANCE = 0.3 diff --git a/homeassistant/components/generic_thermostat/strings.json b/homeassistant/components/generic_thermostat/strings.json index 6c8876d28eb..5257be051a2 100644 --- a/homeassistant/components/generic_thermostat/strings.json +++ b/homeassistant/components/generic_thermostat/strings.json @@ -18,6 +18,7 @@ "cold_tolerance": "Cold tolerance", "heater": "Actuator switch", "hot_tolerance": "Hot tolerance", + "keep_alive": "Keep-alive interval", "max_temp": "Maximum target temperature", "min_cycle_duration": "Minimum cycle duration", "min_temp": "Minimum target temperature", @@ -29,6 +30,7 @@ "cold_tolerance": "Minimum amount of difference between the temperature read by the temperature sensor the target temperature that must change prior to being switched on. For example, if the target temperature is 25 and the tolerance is 0.5 the heater will start when the sensor goes below 24.5.", "heater": "Switch entity used to cool or heat depending on A/C mode.", "hot_tolerance": "Minimum amount of difference between the temperature read by the temperature sensor the target temperature that must change prior to being switched off. For example, if the target temperature is 25 and the tolerance is 0.5 the heater will stop when the sensor equals or goes above 25.5.", + "keep_alive": "Trigger the heater periodically to keep devices from losing state. When set, min cycle duration is ignored.", "min_cycle_duration": "Set a minimum amount of time that the switch specified must be in its current state prior to being switched either off or on.", "target_sensor": "Temperature sensor that reflects the current temperature." }, @@ -45,6 +47,7 @@ "cold_tolerance": "[%key:component::generic_thermostat::config::step::user::data::cold_tolerance%]", "heater": "[%key:component::generic_thermostat::config::step::user::data::heater%]", "hot_tolerance": "[%key:component::generic_thermostat::config::step::user::data::hot_tolerance%]", + "keep_alive": "[%key:component::generic_thermostat::config::step::user::data::keep_alive%]", "max_temp": "[%key:component::generic_thermostat::config::step::user::data::max_temp%]", "min_cycle_duration": "[%key:component::generic_thermostat::config::step::user::data::min_cycle_duration%]", "min_temp": "[%key:component::generic_thermostat::config::step::user::data::min_temp%]", @@ -55,6 +58,7 @@ "cold_tolerance": "[%key:component::generic_thermostat::config::step::user::data_description::cold_tolerance%]", "heater": "[%key:component::generic_thermostat::config::step::user::data_description::heater%]", "hot_tolerance": "[%key:component::generic_thermostat::config::step::user::data_description::hot_tolerance%]", + "keep_alive": "[%key:component::generic_thermostat::config::step::user::data_description::keep_alive%]", "min_cycle_duration": "[%key:component::generic_thermostat::config::step::user::data_description::min_cycle_duration%]", "target_sensor": "[%key:component::generic_thermostat::config::step::user::data_description::target_sensor%]" } diff --git a/homeassistant/components/geniushub/switch.py b/homeassistant/components/geniushub/switch.py index 890ca1578be..874bd0cee7b 100644 --- a/homeassistant/components/geniushub/switch.py +++ b/homeassistant/components/geniushub/switch.py @@ -57,7 +57,7 @@ class GeniusSwitch(GeniusZone, SwitchEntity): """Representation of a Genius Hub switch.""" @property - def device_class(self): + def device_class(self) -> SwitchDeviceClass: """Return the class of this device, from component DEVICE_CLASSES.""" return SwitchDeviceClass.OUTLET diff --git a/homeassistant/components/google_air_quality/icons.json b/homeassistant/components/google_air_quality/icons.json index 197c201d8ee..b3f3370b0b8 100644 --- a/homeassistant/components/google_air_quality/icons.json +++ b/homeassistant/components/google_air_quality/icons.json @@ -1,14 +1,20 @@ { "entity": { "sensor": { - "nitrogen_dioxide": { + "ammonia": { + "default": "mdi:molecule" + }, + "benzene": { + "default": "mdi:molecule" + }, + "nitrogen_monoxide": { + "default": "mdi:molecule" + }, + "non_methane_hydrocarbons": { "default": "mdi:molecule" }, "ozone": { "default": "mdi:molecule" - }, - "sulphur_dioxide": { - "default": "mdi:molecule" } } } diff --git a/homeassistant/components/google_air_quality/manifest.json b/homeassistant/components/google_air_quality/manifest.json index 05b7fe1ae64..7848990961d 100644 --- a/homeassistant/components/google_air_quality/manifest.json +++ b/homeassistant/components/google_air_quality/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["google_air_quality_api"], "quality_scale": "bronze", - "requirements": ["google_air_quality_api==2.1.2"] + "requirements": ["google_air_quality_api==3.0.0"] } diff --git a/homeassistant/components/google_air_quality/sensor.py b/homeassistant/components/google_air_quality/sensor.py index c48d6771976..ac384aa3ff5 100644 --- a/homeassistant/components/google_air_quality/sensor.py +++ b/homeassistant/components/google_air_quality/sensor.py @@ -13,7 +13,11 @@ from homeassistant.components.sensor import ( SensorStateClass, ) from homeassistant.config_entries import ConfigSubentry -from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE +from homeassistant.const import ( + CONCENTRATION_PARTS_PER_MILLION, + CONF_LATITUDE, + CONF_LONGITUDE, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback @@ -99,18 +103,53 @@ AIR_QUALITY_SENSOR_TYPES: tuple[AirQualitySensorEntityDescription, ...] = ( "local_aqi": data.indexes[1].display_name }, ), + AirQualitySensorEntityDescription( + key="c6h6", + translation_key="benzene", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement_fn=lambda x: x.pollutants.c6h6.concentration.units, + value_fn=lambda x: x.pollutants.c6h6.concentration.value, + exists_fn=lambda x: "c6h6" in {p.code for p in x.pollutants}, + ), AirQualitySensorEntityDescription( key="co", state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.CO, native_unit_of_measurement_fn=lambda x: x.pollutants.co.concentration.units, + exists_fn=lambda x: "co" in {p.code for p in x.pollutants}, value_fn=lambda x: x.pollutants.co.concentration.value, + suggested_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + ), + AirQualitySensorEntityDescription( + key="nh3", + translation_key="ammonia", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement_fn=lambda x: x.pollutants.nh3.concentration.units, + value_fn=lambda x: x.pollutants.nh3.concentration.value, + exists_fn=lambda x: "nh3" in {p.code for p in x.pollutants}, + ), + AirQualitySensorEntityDescription( + key="nmhc", + translation_key="non_methane_hydrocarbons", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement_fn=lambda x: x.pollutants.nmhc.concentration.units, + value_fn=lambda x: x.pollutants.nmhc.concentration.value, + exists_fn=lambda x: "nmhc" in {p.code for p in x.pollutants}, + ), + AirQualitySensorEntityDescription( + key="no", + translation_key="nitrogen_monoxide", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement_fn=lambda x: x.pollutants.no.concentration.units, + value_fn=lambda x: x.pollutants.no.concentration.value, + exists_fn=lambda x: "no" in {p.code for p in x.pollutants}, ), AirQualitySensorEntityDescription( key="no2", - translation_key="nitrogen_dioxide", state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.NITROGEN_DIOXIDE, native_unit_of_measurement_fn=lambda x: x.pollutants.no2.concentration.units, + exists_fn=lambda x: "no2" in {p.code for p in x.pollutants}, value_fn=lambda x: x.pollutants.no2.concentration.value, ), AirQualitySensorEntityDescription( @@ -118,6 +157,7 @@ AIR_QUALITY_SENSOR_TYPES: tuple[AirQualitySensorEntityDescription, ...] = ( translation_key="ozone", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement_fn=lambda x: x.pollutants.o3.concentration.units, + exists_fn=lambda x: "o3" in {p.code for p in x.pollutants}, value_fn=lambda x: x.pollutants.o3.concentration.value, ), AirQualitySensorEntityDescription( @@ -125,6 +165,7 @@ AIR_QUALITY_SENSOR_TYPES: tuple[AirQualitySensorEntityDescription, ...] = ( state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.PM10, native_unit_of_measurement_fn=lambda x: x.pollutants.pm10.concentration.units, + exists_fn=lambda x: "pm10" in {p.code for p in x.pollutants}, value_fn=lambda x: x.pollutants.pm10.concentration.value, ), AirQualitySensorEntityDescription( @@ -132,13 +173,15 @@ AIR_QUALITY_SENSOR_TYPES: tuple[AirQualitySensorEntityDescription, ...] = ( state_class=SensorStateClass.MEASUREMENT, device_class=SensorDeviceClass.PM25, native_unit_of_measurement_fn=lambda x: x.pollutants.pm25.concentration.units, + exists_fn=lambda x: "pm25" in {p.code for p in x.pollutants}, value_fn=lambda x: x.pollutants.pm25.concentration.value, ), AirQualitySensorEntityDescription( key="so2", - translation_key="sulphur_dioxide", state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.SULPHUR_DIOXIDE, native_unit_of_measurement_fn=lambda x: x.pollutants.so2.concentration.units, + exists_fn=lambda x: "so2" in {p.code for p in x.pollutants}, value_fn=lambda x: x.pollutants.so2.concentration.value, ), ) diff --git a/homeassistant/components/google_air_quality/strings.json b/homeassistant/components/google_air_quality/strings.json index 8c2a7e75207..8ca0dfcef98 100644 --- a/homeassistant/components/google_air_quality/strings.json +++ b/homeassistant/components/google_air_quality/strings.json @@ -76,6 +76,12 @@ }, "entity": { "sensor": { + "ammonia": { + "name": "Ammonia" + }, + "benzene": { + "name": "Benzene" + }, "local_aqi": { "name": "{local_aqi} AQI" }, @@ -189,6 +195,9 @@ "name": "{local_aqi} dominant pollutant", "state": { "co": "[%key:component::sensor::entity_component::carbon_monoxide::name%]", + "nh3": "[%key:component::google_air_quality::entity::sensor::ammonia::name%]", + "nmhc": "[%key:component::google_air_quality::entity::sensor::non_methane_hydrocarbons::name%]", + "no": "[%key:component::sensor::entity_component::nitrogen_monoxide::name%]", "no2": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]", "o3": "[%key:component::sensor::entity_component::ozone::name%]", "pm10": "[%key:component::sensor::entity_component::pm10::name%]", @@ -196,15 +205,15 @@ "so2": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]" } }, - "nitrogen_dioxide": { - "name": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]" + "nitrogen_monoxide": { + "name": "[%key:component::sensor::entity_component::nitrogen_monoxide::name%]" + }, + "non_methane_hydrocarbons": { + "name": "Non-methane hydrocarbons" }, "ozone": { "name": "[%key:component::sensor::entity_component::ozone::name%]" }, - "sulphur_dioxide": { - "name": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]" - }, "uaqi": { "name": "Universal Air Quality Index" }, diff --git a/homeassistant/components/google_generative_ai_conversation/manifest.json b/homeassistant/components/google_generative_ai_conversation/manifest.json index c23c68982a5..073215bfaf6 100644 --- a/homeassistant/components/google_generative_ai_conversation/manifest.json +++ b/homeassistant/components/google_generative_ai_conversation/manifest.json @@ -8,5 +8,5 @@ "documentation": "https://www.home-assistant.io/integrations/google_generative_ai_conversation", "integration_type": "service", "iot_class": "cloud_polling", - "requirements": ["google-genai==1.56.0"] + "requirements": ["google-genai==1.59.0"] } diff --git a/homeassistant/components/gree/manifest.json b/homeassistant/components/gree/manifest.json index dba8cd6077c..e10b9141911 100644 --- a/homeassistant/components/gree/manifest.json +++ b/homeassistant/components/gree/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/gree", "iot_class": "local_polling", "loggers": ["greeclimate"], - "requirements": ["greeclimate==2.1.0"] + "requirements": ["greeclimate==2.1.1"] } diff --git a/homeassistant/components/group/sensor.py b/homeassistant/components/group/sensor.py index b67e10dd960..078b6a29739 100644 --- a/homeassistant/components/group/sensor.py +++ b/homeassistant/components/group/sensor.py @@ -346,7 +346,6 @@ class SensorGroup(GroupEntity, SensorEntity): self._attr_name = name if name == DEFAULT_NAME: self._attr_name = f"{DEFAULT_NAME} {sensor_type}".capitalize() - self._attr_extra_state_attributes = {ATTR_ENTITY_ID: entity_ids} self._attr_unique_id = unique_id self._ignore_non_numeric = ignore_non_numeric self.mode = all if ignore_non_numeric is False else any @@ -374,7 +373,7 @@ class SensorGroup(GroupEntity, SensorEntity): def async_update_group_state(self) -> None: """Query all members and determine the sensor group state.""" self.calculate_state_attributes(self._get_valid_entities()) - states: list[str] = [] + states: list[str | None] = [] valid_units = self._valid_units valid_states: list[bool] = [] sensor_values: list[tuple[str, float, State]] = [] @@ -435,9 +434,12 @@ class SensorGroup(GroupEntity, SensorEntity): state.attributes.get("unit_of_measurement"), self.entity_id, ) + else: + states.append(None) + valid_states.append(False) - # Set group as unavailable if all members do not have numeric values - self._attr_available = any(numeric_state for numeric_state in valid_states) + # Set group as unavailable if all members are unavailable or missing + self._attr_available = not all(s in (STATE_UNAVAILABLE, None) for s in states) valid_state = self.mode( state not in (STATE_UNKNOWN, STATE_UNAVAILABLE) for state in states @@ -446,6 +448,7 @@ class SensorGroup(GroupEntity, SensorEntity): if not valid_state or not valid_state_numeric: self._attr_native_value = None + self._extra_state_attribute = {} return # Calculate values diff --git a/homeassistant/components/habitica/strings.json b/homeassistant/components/habitica/strings.json index 3896dcb8ff0..17aed3a1094 100644 --- a/homeassistant/components/habitica/strings.json +++ b/homeassistant/components/habitica/strings.json @@ -83,6 +83,9 @@ "invalid_credentials": "Input is incomplete. You must provide either your login details or an API token", "unknown": "[%key:common::config_flow::error::unknown%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "advanced": { "data": { diff --git a/homeassistant/components/hassio/__init__.py b/homeassistant/components/hassio/__init__.py index a1f30276d1f..860f938ef35 100644 --- a/homeassistant/components/hassio/__init__.py +++ b/homeassistant/components/hassio/__init__.py @@ -16,7 +16,7 @@ from aiohasupervisor.models import GreenOptions, YellowOptions # noqa: F401 import voluptuous as vol from homeassistant.auth.const import GROUP_ID_ADMIN -from homeassistant.components import panel_custom +from homeassistant.components import frontend, panel_custom from homeassistant.components.homeassistant import async_set_stop_handler from homeassistant.components.http import StaticPathConfig from homeassistant.config_entries import SOURCE_SYSTEM, ConfigEntry @@ -292,6 +292,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa: return False async_load_websocket_api(hass) + frontend.async_register_built_in_panel(hass, "app") host = os.environ["SUPERVISOR"] websession = async_get_clientsession(hass) diff --git a/homeassistant/components/hassio/addon_panel.py b/homeassistant/components/hassio/addon_panel.py index f0ccecb22f1..67796b52c5e 100644 --- a/homeassistant/components/hassio/addon_panel.py +++ b/homeassistant/components/hassio/addon_panel.py @@ -6,7 +6,7 @@ from typing import Any from aiohttp import web -from homeassistant.components import frontend, panel_custom +from homeassistant.components import frontend from homeassistant.components.http import HomeAssistantView from homeassistant.const import ATTR_ICON from homeassistant.core import HomeAssistant @@ -33,7 +33,7 @@ async def async_setup_addon_panel(hass: HomeAssistant, hassio: HassIO) -> None: # _register_panel never suspends and is only # a coroutine because it would be a breaking change # to make it a normal function - await _register_panel(hass, addon, data) + _register_panel(hass, addon, data) class HassIOAddonPanel(HomeAssistantView): @@ -58,7 +58,7 @@ class HassIOAddonPanel(HomeAssistantView): data = panels[addon] # Register panel - await _register_panel(self.hass, addon, data) + _register_panel(self.hass, addon, data) return web.Response() async def delete(self, request: web.Request, addon: str) -> web.Response: @@ -76,18 +76,14 @@ class HassIOAddonPanel(HomeAssistantView): return {} -async def _register_panel( - hass: HomeAssistant, addon: str, data: dict[str, Any] -) -> None: +def _register_panel(hass: HomeAssistant, addon: str, data: dict[str, Any]): """Init coroutine to register the panel.""" - await panel_custom.async_register_panel( + frontend.async_register_built_in_panel( hass, + "app", frontend_url_path=addon, - webcomponent_name="hassio-main", sidebar_title=data[ATTR_TITLE], sidebar_icon=data[ATTR_ICON], - js_url="/api/hassio/app/entrypoint.js", - embed_iframe=True, require_admin=data[ATTR_ADMIN], - config={"ingress": addon}, + config={"addon": addon}, ) diff --git a/homeassistant/components/hdfury/__init__.py b/homeassistant/components/hdfury/__init__.py index 8eaf51a3aa0..fcf40cbbac0 100644 --- a/homeassistant/components/hdfury/__init__.py +++ b/homeassistant/components/hdfury/__init__.py @@ -8,6 +8,7 @@ from .coordinator import HDFuryConfigEntry, HDFuryCoordinator PLATFORMS = [ Platform.BUTTON, Platform.SELECT, + Platform.SENSOR, Platform.SWITCH, ] diff --git a/homeassistant/components/hdfury/button.py b/homeassistant/components/hdfury/button.py index d56864c1f5e..6b2a292c210 100644 --- a/homeassistant/components/hdfury/button.py +++ b/homeassistant/components/hdfury/button.py @@ -19,6 +19,8 @@ from .const import DOMAIN from .coordinator import HDFuryConfigEntry from .entity import HDFuryEntity +PARALLEL_UPDATES = 1 + @dataclass(kw_only=True, frozen=True) class HDFuryButtonEntityDescription(ButtonEntityDescription): diff --git a/homeassistant/components/hdfury/diagnostics.py b/homeassistant/components/hdfury/diagnostics.py new file mode 100644 index 00000000000..c561a97d4ee --- /dev/null +++ b/homeassistant/components/hdfury/diagnostics.py @@ -0,0 +1,21 @@ +"""Diagnostics for HDFury Integration.""" + +from typing import Any + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant + +from .coordinator import HDFuryCoordinator + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, entry: ConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + coordinator: HDFuryCoordinator = entry.runtime_data + + return { + "board": coordinator.data.board, + "info": coordinator.data.info, + "config": coordinator.data.config, + } diff --git a/homeassistant/components/hdfury/icons.json b/homeassistant/components/hdfury/icons.json index 9088ee37eaa..3590f512418 100644 --- a/homeassistant/components/hdfury/icons.json +++ b/homeassistant/components/hdfury/icons.json @@ -16,6 +16,50 @@ "default": "mdi:hdmi-port" } }, + "sensor": { + "aud0": { + "default": "mdi:audio-input-rca" + }, + "aud1": { + "default": "mdi:audio-input-rca" + }, + "audout": { + "default": "mdi:television-speaker" + }, + "earcrx": { + "default": "mdi:audio-video" + }, + "edida0": { + "default": "mdi:format-list-text" + }, + "edida1": { + "default": "mdi:format-list-text" + }, + "edida2": { + "default": "mdi:format-list-text" + }, + "rx0": { + "default": "mdi:video-input-hdmi" + }, + "rx1": { + "default": "mdi:video-input-hdmi" + }, + "sink0": { + "default": "mdi:television" + }, + "sink1": { + "default": "mdi:television" + }, + "sink2": { + "default": "mdi:audio-video" + }, + "tx0": { + "default": "mdi:cable-data" + }, + "tx1": { + "default": "mdi:cable-data" + } + }, "switch": { "autosw": { "default": "mdi:import" diff --git a/homeassistant/components/hdfury/manifest.json b/homeassistant/components/hdfury/manifest.json index 93c09362f30..86e044708c9 100644 --- a/homeassistant/components/hdfury/manifest.json +++ b/homeassistant/components/hdfury/manifest.json @@ -6,6 +6,6 @@ "documentation": "https://www.home-assistant.io/integrations/hdfury", "integration_type": "device", "iot_class": "local_polling", - "quality_scale": "bronze", + "quality_scale": "silver", "requirements": ["hdfury==1.3.1"] } diff --git a/homeassistant/components/hdfury/quality_scale.yaml b/homeassistant/components/hdfury/quality_scale.yaml index 614a3344f10..02cae0ebd0c 100644 --- a/homeassistant/components/hdfury/quality_scale.yaml +++ b/homeassistant/components/hdfury/quality_scale.yaml @@ -35,15 +35,15 @@ rules: entity-unavailable: done integration-owner: done log-when-unavailable: done - parallel-updates: todo + parallel-updates: done reauthentication-flow: status: exempt comment: Integration has no authentication flow. - test-coverage: todo + test-coverage: done # Gold devices: done - diagnostics: todo + diagnostics: done discovery-update-info: todo discovery: todo docs-data-update: todo diff --git a/homeassistant/components/hdfury/select.py b/homeassistant/components/hdfury/select.py index c0849dc5ca9..7866b07e0f4 100644 --- a/homeassistant/components/hdfury/select.py +++ b/homeassistant/components/hdfury/select.py @@ -20,6 +20,8 @@ from .const import DOMAIN from .coordinator import HDFuryConfigEntry, HDFuryCoordinator from .entity import HDFuryEntity +PARALLEL_UPDATES = 1 + @dataclass(kw_only=True, frozen=True) class HDFurySelectEntityDescription(SelectEntityDescription): @@ -77,13 +79,11 @@ async def async_setup_entry( coordinator = entry.runtime_data - entities: list[HDFuryEntity] = [] - - for description in SELECT_PORTS: - if description.key not in coordinator.data.info: - continue - - entities.append(HDFurySelect(coordinator, description)) + entities: list[HDFuryEntity] = [ + HDFurySelect(coordinator, description) + for description in SELECT_PORTS + if description.key in coordinator.data.info + ] # Add OPMODE select if present if "opmode" in coordinator.data.info: diff --git a/homeassistant/components/hdfury/sensor.py b/homeassistant/components/hdfury/sensor.py new file mode 100644 index 00000000000..23538c5f0f4 --- /dev/null +++ b/homeassistant/components/hdfury/sensor.py @@ -0,0 +1,123 @@ +"""Sensor platform for HDFury Integration.""" + +from homeassistant.components.sensor import SensorEntity, SensorEntityDescription +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from .coordinator import HDFuryConfigEntry +from .entity import HDFuryEntity + +PARALLEL_UPDATES = 0 + +SENSORS: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key="RX0", + translation_key="rx0", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="RX1", + translation_key="rx1", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="TX0", + translation_key="tx0", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="TX1", + translation_key="tx1", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="AUD0", + translation_key="aud0", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="AUD1", + translation_key="aud1", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="AUDOUT", + translation_key="audout", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="EARCRX", + translation_key="earcrx", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="SINK0", + translation_key="sink0", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="SINK1", + translation_key="sink1", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="SINK2", + translation_key="sink2", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="EDIDA0", + translation_key="edida0", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="EDIDA1", + translation_key="edida1", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="EDIDA2", + translation_key="edida2", + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: HDFuryConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up sensors using the platform schema.""" + + coordinator = entry.runtime_data + + async_add_entities( + HDFurySensor(coordinator, description) + for description in SENSORS + if description.key in coordinator.data.info + ) + + +class HDFurySensor(HDFuryEntity, SensorEntity): + """Base HDFury Sensor Class.""" + + entity_description: SensorEntityDescription + + @property + def native_value(self) -> str: + """Set Sensor Value.""" + + return self.coordinator.data.info[self.entity_description.key] diff --git a/homeassistant/components/hdfury/strings.json b/homeassistant/components/hdfury/strings.json index 0aa0d5241a2..d2f1746b211 100644 --- a/homeassistant/components/hdfury/strings.json +++ b/homeassistant/components/hdfury/strings.json @@ -57,6 +57,50 @@ } } }, + "sensor": { + "aud0": { + "name": "Audio TX0" + }, + "aud1": { + "name": "Audio TX1" + }, + "audout": { + "name": "Audio output" + }, + "earcrx": { + "name": "eARC/ARC status" + }, + "edida0": { + "name": "EDID TXA0" + }, + "edida1": { + "name": "EDID TXA1" + }, + "edida2": { + "name": "EDID AUDA" + }, + "rx0": { + "name": "Input RX0" + }, + "rx1": { + "name": "Input RX1" + }, + "sink0": { + "name": "EDID TX0" + }, + "sink1": { + "name": "EDID TX1" + }, + "sink2": { + "name": "EDID AUD" + }, + "tx0": { + "name": "Output TX0" + }, + "tx1": { + "name": "Output TX1" + } + }, "switch": { "autosw": { "name": "Auto switch inputs" diff --git a/homeassistant/components/hdfury/switch.py b/homeassistant/components/hdfury/switch.py index 717aa345f02..066333b196c 100644 --- a/homeassistant/components/hdfury/switch.py +++ b/homeassistant/components/hdfury/switch.py @@ -16,6 +16,8 @@ from .const import DOMAIN from .coordinator import HDFuryConfigEntry from .entity import HDFuryEntity +PARALLEL_UPDATES = 1 + @dataclass(kw_only=True, frozen=True) class HDFurySwitchEntityDescription(SwitchEntityDescription): diff --git a/homeassistant/components/hikvision/__init__.py b/homeassistant/components/hikvision/__init__.py index e3089a6453c..4c044451659 100644 --- a/homeassistant/components/hikvision/__init__.py +++ b/homeassistant/components/hikvision/__init__.py @@ -5,6 +5,7 @@ from __future__ import annotations from dataclasses import dataclass import logging +from pyhik.constants import SENSOR_MAP from pyhik.hikvision import HikCamera import requests @@ -19,10 +20,13 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers import device_registry as dr + +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -PLATFORMS = [Platform.BINARY_SENSOR] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.CAMERA] @dataclass @@ -70,19 +74,49 @@ async def async_setup_entry(hass: HomeAssistant, entry: HikvisionConfigEntry) -> device_type=device_type, ) + _LOGGER.debug( + "Device %s (type=%s) initial event_states: %s", + device_name, + device_type, + camera.current_event_states, + ) + # For NVRs or devices with no detected events, try to fetch events from ISAPI + # Use broader notification methods for NVRs since they often use 'record' etc. if device_type == "NVR" or not camera.current_event_states: + nvr_notification_methods = {"center", "HTTP", "record", "email", "beep"} def fetch_and_inject_nvr_events() -> None: """Fetch and inject NVR events in a single executor job.""" - if nvr_events := camera.get_event_triggers(): - camera.inject_events(nvr_events) + nvr_events = camera.get_event_triggers(nvr_notification_methods) + _LOGGER.debug("NVR events fetched with extended methods: %s", nvr_events) + if nvr_events: + # Map raw event type names to friendly names using SENSOR_MAP + mapped_events: dict[str, list[int]] = {} + for event_type, channels in nvr_events.items(): + friendly_name = SENSOR_MAP.get(event_type.lower(), event_type) + if friendly_name in mapped_events: + mapped_events[friendly_name].extend(channels) + else: + mapped_events[friendly_name] = list(channels) + _LOGGER.debug("Mapped NVR events: %s", mapped_events) + camera.inject_events(mapped_events) await hass.async_add_executor_job(fetch_and_inject_nvr_events) # Start the event stream await hass.async_add_executor_job(camera.start_stream) + # Register the main device before platforms that use via_device + device_registry = dr.async_get(hass) + device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + identifiers={(DOMAIN, device_id)}, + name=device_name, + manufacturer="Hikvision", + model=device_type, + ) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True diff --git a/homeassistant/components/hikvision/binary_sensor.py b/homeassistant/components/hikvision/binary_sensor.py index 6a354458ed3..a529185eda2 100644 --- a/homeassistant/components/hikvision/binary_sensor.py +++ b/homeassistant/components/hikvision/binary_sensor.py @@ -185,19 +185,30 @@ class HikvisionBinarySensor(BinarySensorEntity): # Build unique ID self._attr_unique_id = f"{self._data.device_id}_{sensor_type}_{channel}" - # Build entity name based on device type - if self._data.device_type == "NVR": - self._attr_name = f"{sensor_type} {channel}" - else: - self._attr_name = sensor_type - # Device info for device registry - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, self._data.device_id)}, - name=self._data.device_name, - manufacturer="Hikvision", - model=self._data.device_type, - ) + if self._data.device_type == "NVR": + # NVR channels get their own device linked to the NVR via via_device + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, f"{self._data.device_id}_{channel}")}, + via_device=(DOMAIN, self._data.device_id), + translation_key="nvr_channel", + translation_placeholders={ + "device_name": self._data.device_name, + "channel_number": str(channel), + }, + manufacturer="Hikvision", + model="NVR Channel", + ) + self._attr_name = sensor_type + else: + # Single camera device + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, self._data.device_id)}, + name=self._data.device_name, + manufacturer="Hikvision", + model=self._data.device_type, + ) + self._attr_name = sensor_type # Set device class self._attr_device_class = DEVICE_CLASS_MAP.get(sensor_type) diff --git a/homeassistant/components/hikvision/camera.py b/homeassistant/components/hikvision/camera.py new file mode 100644 index 00000000000..c369c6d3c41 --- /dev/null +++ b/homeassistant/components/hikvision/camera.py @@ -0,0 +1,97 @@ +"""Support for Hikvision cameras.""" + +from __future__ import annotations + +from homeassistant.components.camera import Camera, CameraEntityFeature +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import HikvisionConfigEntry +from .const import DOMAIN + +PARALLEL_UPDATES = 0 + + +async def async_setup_entry( + hass: HomeAssistant, + entry: HikvisionConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Hikvision cameras from a config entry.""" + data = entry.runtime_data + camera = data.camera + + # Get available channels from the library + channels = await hass.async_add_executor_job(camera.get_channels) + + if channels: + entities = [HikvisionCamera(entry, channel) for channel in channels] + else: + # Fallback to single camera if no channels detected + entities = [HikvisionCamera(entry, 1)] + + async_add_entities(entities) + + +class HikvisionCamera(Camera): + """Representation of a Hikvision camera.""" + + _attr_has_entity_name = True + _attr_name = None + _attr_supported_features = CameraEntityFeature.STREAM + + def __init__( + self, + entry: HikvisionConfigEntry, + channel: int, + ) -> None: + """Initialize the camera.""" + super().__init__() + self._data = entry.runtime_data + self._channel = channel + self._camera = self._data.camera + + # Build unique ID (unique per platform per integration) + self._attr_unique_id = f"{self._data.device_id}_{channel}" + + # Device info for device registry + if self._data.device_type == "NVR": + # NVR channels get their own device linked to the NVR via via_device + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, f"{self._data.device_id}_{channel}")}, + via_device=(DOMAIN, self._data.device_id), + translation_key="nvr_channel", + translation_placeholders={ + "device_name": self._data.device_name, + "channel_number": str(channel), + }, + manufacturer="Hikvision", + model="NVR Channel", + ) + else: + # Single camera device + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, self._data.device_id)}, + name=self._data.device_name, + manufacturer="Hikvision", + model=self._data.device_type, + ) + + async def async_camera_image( + self, width: int | None = None, height: int | None = None + ) -> bytes | None: + """Return a still image from the camera.""" + try: + return await self.hass.async_add_executor_job( + self._camera.get_snapshot, self._channel + ) + except Exception as err: + raise HomeAssistantError( + f"Error getting image from {self._data.device_name} channel {self._channel}: {err}" + ) from err + + async def stream_source(self) -> str | None: + """Return the stream source URL.""" + return self._camera.get_stream_url(self._channel) diff --git a/homeassistant/components/hikvision/strings.json b/homeassistant/components/hikvision/strings.json index ca25cccf772..0b5241bdd29 100644 --- a/homeassistant/components/hikvision/strings.json +++ b/homeassistant/components/hikvision/strings.json @@ -29,6 +29,11 @@ } } }, + "device": { + "nvr_channel": { + "name": "{device_name} channel {channel_number}" + } + }, "issues": { "deprecated_yaml_import_issue": { "description": "Configuring {integration_title} using YAML is deprecated and the import failed. Please remove the `{domain}` entry from your `configuration.yaml` file and set up the integration manually.", diff --git a/homeassistant/components/homee/sensor.py b/homeassistant/components/homee/sensor.py index 71508c5d669..5fc19e9bfdf 100644 --- a/homeassistant/components/homee/sensor.py +++ b/homeassistant/components/homee/sensor.py @@ -6,10 +6,7 @@ from dataclasses import dataclass from pyHomee.const import AttributeType, NodeState from pyHomee.model import HomeeAttribute, HomeeNode -from homeassistant.components.automation import automations_with_entity -from homeassistant.components.script import scripts_with_entity from homeassistant.components.sensor import ( - DOMAIN as SENSOR_DOMAIN, SensorDeviceClass, SensorEntity, SensorEntityDescription, @@ -17,17 +14,10 @@ from homeassistant.components.sensor import ( ) from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.helpers.issue_registry import ( - IssueSeverity, - async_create_issue, - async_delete_issue, -) from . import HomeeConfigEntry from .const import ( - DOMAIN, HOMEE_UNIT_TO_HA_UNIT, OPEN_CLOSE_MAP, OPEN_CLOSE_MAP_REVERSED, @@ -109,11 +99,6 @@ SENSOR_DESCRIPTIONS: dict[AttributeType, HomeeSensorEntityDescription] = { device_class=SensorDeviceClass.POWER, state_class=SensorStateClass.MEASUREMENT, ), - AttributeType.CURRENT_VALVE_POSITION: HomeeSensorEntityDescription( - key="valve_position", - entity_category=EntityCategory.DIAGNOSTIC, - state_class=SensorStateClass.MEASUREMENT, - ), AttributeType.DAWN: HomeeSensorEntityDescription( key="dawn", device_class=SensorDeviceClass.ILLUMINANCE, @@ -294,57 +279,12 @@ NODE_SENSOR_DESCRIPTIONS: tuple[HomeeNodeSensorEntityDescription, ...] = ( ) -def entity_used_in(hass: HomeAssistant, entity_id: str) -> list[str]: - """Get list of related automations and scripts.""" - used_in = automations_with_entity(hass, entity_id) - used_in += scripts_with_entity(hass, entity_id) - return used_in - - async def async_setup_entry( hass: HomeAssistant, config_entry: HomeeConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Add the homee platform for the sensor components.""" - ent_reg = er.async_get(hass) - - def add_deprecated_entity( - attribute: HomeeAttribute, description: HomeeSensorEntityDescription - ) -> list[HomeeSensor]: - """Add deprecated entities.""" - deprecated_entities: list[HomeeSensor] = [] - entity_uid = f"{config_entry.runtime_data.settings.uid}-{attribute.node_id}-{attribute.id}" - if entity_id := ent_reg.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, entity_uid): - entity_entry = ent_reg.async_get(entity_id) - if entity_entry and entity_entry.disabled: - ent_reg.async_remove(entity_id) - async_delete_issue( - hass, - DOMAIN, - f"deprecated_entity_{entity_uid}", - ) - elif entity_entry: - deprecated_entities.append( - HomeeSensor(attribute, config_entry, description) - ) - if entity_used_in(hass, entity_id): - async_create_issue( - hass, - DOMAIN, - f"deprecated_entity_{entity_uid}", - breaks_in_ha_version="2025.12.0", - is_fixable=False, - severity=IssueSeverity.WARNING, - translation_key="deprecated_entity", - translation_placeholders={ - "name": str( - entity_entry.name or entity_entry.original_name - ), - "entity": entity_id, - }, - ) - return deprecated_entities async def add_sensor_entities( config_entry: HomeeConfigEntry, @@ -362,19 +302,13 @@ async def async_setup_entry( ) # Node attributes that are sensors. - for attribute in node.attributes: - if attribute.type == AttributeType.CURRENT_VALVE_POSITION: - entities.extend( - add_deprecated_entity( - attribute, SENSOR_DESCRIPTIONS[attribute.type] - ) - ) - elif attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable: - entities.append( - HomeeSensor( - attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type] - ) - ) + entities.extend( + HomeeSensor( + attribute, config_entry, SENSOR_DESCRIPTIONS[attribute.type] + ) + for attribute in node.attributes + if attribute.type in SENSOR_DESCRIPTIONS and not attribute.editable + ) if entities: async_add_entities(entities) diff --git a/homeassistant/components/homee/strings.json b/homeassistant/components/homee/strings.json index 535c5b9628a..9187c9956c7 100644 --- a/homeassistant/components/homee/strings.json +++ b/homeassistant/components/homee/strings.json @@ -495,11 +495,5 @@ "invalid_preset_mode": { "message": "Invalid preset mode: {preset_mode}. Turning on is only supported with preset mode 'Manual'." } - }, - "issues": { - "deprecated_entity": { - "description": "The Homee entity `{entity}` is deprecated and will be removed in release 2025.12.\nThe valve is available directly in the respective climate entity.\nPlease update your automations and scripts, disable `{entity}` and reload the integration/restart Home Assistant to fix this issue.", - "title": "The Homee {name} entity is deprecated" - } } } diff --git a/homeassistant/components/homekit/accessories.py b/homeassistant/components/homekit/accessories.py index b9840fb2b68..06fc0a1c493 100644 --- a/homeassistant/components/homekit/accessories.py +++ b/homeassistant/components/homekit/accessories.py @@ -220,31 +220,33 @@ def get_accessory( # noqa: C901 a_type = "TemperatureSensor" elif device_class == SensorDeviceClass.HUMIDITY and unit == PERCENTAGE: a_type = "HumiditySensor" - elif ( - device_class == SensorDeviceClass.PM10 - or SensorDeviceClass.PM10 in state.entity_id - ): + elif device_class == SensorDeviceClass.PM10: a_type = "PM10Sensor" - elif ( - device_class == SensorDeviceClass.PM25 - or SensorDeviceClass.PM25 in state.entity_id - ): + elif device_class == SensorDeviceClass.PM25: a_type = "PM25Sensor" elif device_class == SensorDeviceClass.NITROGEN_DIOXIDE: a_type = "NitrogenDioxideSensor" elif device_class == SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: a_type = "VolatileOrganicCompoundsSensor" - elif ( - device_class == SensorDeviceClass.GAS - or SensorDeviceClass.GAS in state.entity_id - ): + elif device_class == SensorDeviceClass.GAS: a_type = "AirQualitySensor" elif device_class == SensorDeviceClass.CO: a_type = "CarbonMonoxideSensor" - elif device_class == SensorDeviceClass.CO2 or "co2" in state.entity_id: + elif device_class == SensorDeviceClass.CO2: a_type = "CarbonDioxideSensor" elif device_class == SensorDeviceClass.ILLUMINANCE or unit == LIGHT_LUX: a_type = "LightSensor" + + # Fallbacks based on entity_id + elif SensorDeviceClass.PM10 in state.entity_id: + a_type = "PM10Sensor" + elif SensorDeviceClass.PM25 in state.entity_id: + a_type = "PM25Sensor" + elif SensorDeviceClass.GAS in state.entity_id: + a_type = "AirQualitySensor" + elif "co2" in state.entity_id: + a_type = "CarbonDioxideSensor" + else: _LOGGER.debug( "%s: Unsupported sensor type (device_class=%s) (unit=%s)", diff --git a/homeassistant/components/homematic/binary_sensor.py b/homeassistant/components/homematic/binary_sensor.py index 0d94c2bb78b..e2090b74ce8 100644 --- a/homeassistant/components/homematic/binary_sensor.py +++ b/homeassistant/components/homematic/binary_sensor.py @@ -59,21 +59,21 @@ class HMBinarySensor(HMDevice, BinarySensorEntity): """Representation of a binary HomeMatic device.""" @property - def is_on(self): + def is_on(self) -> bool: """Return true if switch is on.""" if not self.available: return False return bool(self._hm_get_state()) @property - def device_class(self): + def device_class(self) -> BinarySensorDeviceClass | None: """Return the class of this sensor from DEVICE_CLASSES.""" # If state is MOTION (Only RemoteMotion working) if self._state == "MOTION": return BinarySensorDeviceClass.MOTION return SENSOR_TYPES_CLASS.get(self._hmdevice.__class__.__name__) - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate the data dictionary (self._data) from metadata.""" # Add state to data struct if self._state: @@ -86,11 +86,11 @@ class HMBatterySensor(HMDevice, BinarySensorEntity): _attr_device_class = BinarySensorDeviceClass.BATTERY @property - def is_on(self): + def is_on(self) -> bool: """Return True if battery is low.""" return bool(self._hm_get_state()) - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate the data dictionary (self._data) from metadata.""" # Add state to data struct if self._state: diff --git a/homeassistant/components/homematic/climate.py b/homeassistant/components/homematic/climate.py index 28943774b6c..096ad76db11 100644 --- a/homeassistant/components/homematic/climate.py +++ b/homeassistant/components/homematic/climate.py @@ -178,7 +178,7 @@ class HMThermostat(HMDevice, ClimateEntity): # Homematic return self._data.get("CONTROL_MODE") - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate a data dict (self._data) from the Homematic metadata.""" self._state = next(iter(self._hmdevice.WRITENODE.keys())) self._data[self._state] = None diff --git a/homeassistant/components/homematic/cover.py b/homeassistant/components/homematic/cover.py index b9f4a4fa96a..f93d92eed56 100644 --- a/homeassistant/components/homematic/cover.py +++ b/homeassistant/components/homematic/cover.py @@ -78,7 +78,7 @@ class HMCover(HMDevice, CoverEntity): """Stop the device if in motion.""" self._hmdevice.stop(self._channel) - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate a data dictionary (self._data) from metadata.""" self._state = "LEVEL" self._data.update({self._state: None}) @@ -138,7 +138,7 @@ class HMGarage(HMCover): """Return whether the cover is closed.""" return self._hmdevice.is_closed(self._hm_get_state()) - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate a data dictionary (self._data) from metadata.""" self._state = "DOOR_STATE" self._data.update({self._state: None}) diff --git a/homeassistant/components/homematic/entity.py b/homeassistant/components/homematic/entity.py index 3b5d2ebb509..3e4d6a6fc71 100644 --- a/homeassistant/components/homematic/entity.py +++ b/homeassistant/components/homematic/entity.py @@ -204,7 +204,7 @@ class HMDevice(Entity): self._init_data_struct() @abstractmethod - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate a data dictionary from the HomeMatic device metadata.""" diff --git a/homeassistant/components/homematic/light.py b/homeassistant/components/homematic/light.py index 838cdc9c3c3..62ce1cc9457 100644 --- a/homeassistant/components/homematic/light.py +++ b/homeassistant/components/homematic/light.py @@ -51,7 +51,7 @@ class HMLight(HMDevice, LightEntity): _attr_max_color_temp_kelvin = 6500 # 153 Mireds @property - def brightness(self): + def brightness(self) -> int | None: """Return the brightness of this light between 0..255.""" # Is dimmer? if self._state == "LEVEL": @@ -59,7 +59,7 @@ class HMLight(HMDevice, LightEntity): return None @property - def is_on(self): + def is_on(self) -> bool: """Return true if light is on.""" try: return self._hm_get_state() > 0 @@ -98,7 +98,7 @@ class HMLight(HMDevice, LightEntity): return features @property - def hs_color(self): + def hs_color(self) -> tuple[float, float] | None: """Return the hue and saturation color value [float, float].""" if ColorMode.HS not in self.supported_color_modes: return None @@ -116,14 +116,14 @@ class HMLight(HMDevice, LightEntity): ) @property - def effect_list(self): + def effect_list(self) -> list[str] | None: """Return the list of supported effects.""" if not self.supported_features & LightEntityFeature.EFFECT: return None return self._hmdevice.get_effect_list() @property - def effect(self): + def effect(self) -> str | None: """Return the current color change program of the light.""" if not self.supported_features & LightEntityFeature.EFFECT: return None @@ -166,7 +166,7 @@ class HMLight(HMDevice, LightEntity): self._hmdevice.off(self._channel) - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate a data dict (self._data) from the Homematic metadata.""" # Use LEVEL self._state = "LEVEL" diff --git a/homeassistant/components/homematic/lock.py b/homeassistant/components/homematic/lock.py index b79f28f2bc7..7640146b422 100644 --- a/homeassistant/components/homematic/lock.py +++ b/homeassistant/components/homematic/lock.py @@ -48,7 +48,7 @@ class HMLock(HMDevice, LockEntity): """Open the door latch.""" self._hmdevice.open() - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate the data dictionary (self._data) from metadata.""" self._state = "STATE" self._data.update({self._state: None}) diff --git a/homeassistant/components/homematic/notify.py b/homeassistant/components/homematic/notify.py index 1f89abea5cc..b4a2692a417 100644 --- a/homeassistant/components/homematic/notify.py +++ b/homeassistant/components/homematic/notify.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import Any + import voluptuous as vol from homeassistant.components.notify import ( @@ -60,7 +62,7 @@ class HomematicNotificationService(BaseNotificationService): self.hass = hass self.data = data - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a notification to the device.""" data = {**self.data, **kwargs.get(ATTR_DATA, {})} diff --git a/homeassistant/components/homematic/sensor.py b/homeassistant/components/homematic/sensor.py index bdd446d7091..0ddc319626e 100644 --- a/homeassistant/components/homematic/sensor.py +++ b/homeassistant/components/homematic/sensor.py @@ -339,7 +339,7 @@ class HMSensor(HMDevice, SensorEntity): # No cast, return original value return self._hm_get_state() - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate a data dictionary (self._data) from metadata.""" if self._state: self._data.update({self._state: None}) diff --git a/homeassistant/components/homematic/switch.py b/homeassistant/components/homematic/switch.py index 5f7c1f93dc8..ac8a2e5fe14 100644 --- a/homeassistant/components/homematic/switch.py +++ b/homeassistant/components/homematic/switch.py @@ -35,7 +35,7 @@ class HMSwitch(HMDevice, SwitchEntity): """Representation of a HomeMatic switch.""" @property - def is_on(self): + def is_on(self) -> bool: """Return True if switch is on.""" try: return self._hm_get_state() > 0 @@ -43,7 +43,7 @@ class HMSwitch(HMDevice, SwitchEntity): return False @property - def today_energy_kwh(self): + def today_energy_kwh(self) -> float | None: """Return the current power usage in kWh.""" if "ENERGY_COUNTER" in self._data: try: @@ -61,7 +61,7 @@ class HMSwitch(HMDevice, SwitchEntity): """Turn the switch off.""" self._hmdevice.off(self._channel) - def _init_data_struct(self): + def _init_data_struct(self) -> None: """Generate the data dictionary (self._data) from metadata.""" self._state = "STATE" self._data.update({self._state: None}) diff --git a/homeassistant/components/homewizard/manifest.json b/homeassistant/components/homewizard/manifest.json index 63500eb1f71..c008ec02b0a 100644 --- a/homeassistant/components/homewizard/manifest.json +++ b/homeassistant/components/homewizard/manifest.json @@ -13,6 +13,6 @@ "iot_class": "local_polling", "loggers": ["homewizard_energy"], "quality_scale": "platinum", - "requirements": ["python-homewizard-energy==10.0.0"], + "requirements": ["python-homewizard-energy==10.0.1"], "zeroconf": ["_hwenergy._tcp.local.", "_homewizard._tcp.local."] } diff --git a/homeassistant/components/html5/notify.py b/homeassistant/components/html5/notify.py index e9ebdb9da67..859a7b7e567 100644 --- a/homeassistant/components/html5/notify.py +++ b/homeassistant/components/html5/notify.py @@ -9,6 +9,7 @@ from http import HTTPStatus import json import logging import time +from typing import Any from urllib.parse import urlparse import uuid @@ -451,7 +452,7 @@ class HTML5NotificationService(BaseNotificationService): """ await self.hass.async_add_executor_job(partial(self.dismiss, **kwargs)) - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" tag = str(uuid.uuid4()) payload = { diff --git a/homeassistant/components/hue/v1/sensor_base.py b/homeassistant/components/hue/v1/sensor_base.py index fb8f3c572c1..0ea079992e0 100644 --- a/homeassistant/components/hue/v1/sensor_base.py +++ b/homeassistant/components/hue/v1/sensor_base.py @@ -181,7 +181,7 @@ class GenericHueSensor(GenericHueDevice, entity.Entity): # pylint: disable=hass ) @property - def state_class(self): + def state_class(self) -> SensorStateClass: """Return the state class of this entity, from STATE_CLASSES, if any.""" return SensorStateClass.MEASUREMENT diff --git a/homeassistant/components/icloud/manifest.json b/homeassistant/components/icloud/manifest.json index 318be5cca98..ea8f52732cf 100644 --- a/homeassistant/components/icloud/manifest.json +++ b/homeassistant/components/icloud/manifest.json @@ -7,5 +7,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["keyrings.alt", "pyicloud"], - "requirements": ["pyicloud==2.2.0"] + "requirements": ["pyicloud==2.3.0"] } diff --git a/homeassistant/components/joaoapps_join/notify.py b/homeassistant/components/joaoapps_join/notify.py index a3432b96b13..6a1e7bb8e6d 100644 --- a/homeassistant/components/joaoapps_join/notify.py +++ b/homeassistant/components/joaoapps_join/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any from pyjoin import get_devices, send_notification import voluptuous as vol @@ -66,7 +67,7 @@ class JoinNotificationService(BaseNotificationService): self._device_ids = device_ids self._device_names = device_names - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) data = kwargs.get(ATTR_DATA) or {} diff --git a/homeassistant/components/jvc_projector/__init__.py b/homeassistant/components/jvc_projector/__init__.py index ad7e333ca13..547b0a67761 100644 --- a/homeassistant/components/jvc_projector/__init__.py +++ b/homeassistant/components/jvc_projector/__init__.py @@ -2,7 +2,7 @@ from __future__ import annotations -from jvcprojector import JvcProjector, JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector import JvcProjector, JvcProjectorAuthError, JvcProjectorTimeoutError from homeassistant.const import ( CONF_HOST, @@ -11,8 +11,9 @@ from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, Platform, ) -from homeassistant.core import Event, HomeAssistant +from homeassistant.core import Event, HomeAssistant, callback from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady +from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries from .coordinator import JVCConfigEntry, JvcProjectorDataUpdateCoordinator @@ -28,8 +29,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: JVCConfigEntry) -> bool: ) try: - await device.connect(True) - except JvcProjectorConnectError as err: + await device.connect() + except JvcProjectorTimeoutError as err: await device.disconnect() raise ConfigEntryNotReady( f"Unable to connect to {entry.data[CONF_HOST]}" @@ -50,6 +51,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: JVCConfigEntry) -> bool: hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, disconnect) ) + await async_migrate_entities(hass, entry, coordinator) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True @@ -60,3 +63,21 @@ async def async_unload_entry(hass: HomeAssistant, entry: JVCConfigEntry) -> bool if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): await entry.runtime_data.device.disconnect() return unload_ok + + +async def async_migrate_entities( + hass: HomeAssistant, + config_entry: JVCConfigEntry, + coordinator: JvcProjectorDataUpdateCoordinator, +) -> None: + """Migrate old entities as needed.""" + + @callback + def _update_entry(entry: RegistryEntry) -> dict[str, str] | None: + """Fix unique_id of power binary_sensor entry.""" + if entry.domain == Platform.BINARY_SENSOR and ":" not in entry.unique_id: + if "_power" in entry.unique_id: + return {"new_unique_id": f"{coordinator.unique_id}_power"} + return None + + await async_migrate_entries(hass, config_entry.entry_id, _update_entry) diff --git a/homeassistant/components/jvc_projector/binary_sensor.py b/homeassistant/components/jvc_projector/binary_sensor.py index 7ae76298839..86e3e104f32 100644 --- a/homeassistant/components/jvc_projector/binary_sensor.py +++ b/homeassistant/components/jvc_projector/binary_sensor.py @@ -2,16 +2,17 @@ from __future__ import annotations -from jvcprojector import const +from jvcprojector import command as cmd from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from .const import POWER from .coordinator import JVCConfigEntry, JvcProjectorDataUpdateCoordinator from .entity import JvcProjectorEntity -ON_STATUS = (const.ON, const.WARMING) +ON_STATUS = (cmd.Power.ON, cmd.Power.WARMING) async def async_setup_entry( @@ -21,14 +22,13 @@ async def async_setup_entry( ) -> None: """Set up the JVC Projector platform from a config entry.""" coordinator = entry.runtime_data - async_add_entities([JvcBinarySensor(coordinator)]) class JvcBinarySensor(JvcProjectorEntity, BinarySensorEntity): """The entity class for JVC Projector Binary Sensor.""" - _attr_translation_key = "jvc_power" + _attr_translation_key = "power" def __init__( self, @@ -36,9 +36,9 @@ class JvcBinarySensor(JvcProjectorEntity, BinarySensorEntity): ) -> None: """Initialize the JVC Projector sensor.""" super().__init__(coordinator) - self._attr_unique_id = f"{coordinator.device.mac}_power" + self._attr_unique_id = f"{coordinator.unique_id}_power" @property def is_on(self) -> bool: - """Return true if the JVC is on.""" - return self.coordinator.data["power"] in ON_STATUS + """Return true if the JVC Projector is on.""" + return self.coordinator.data[POWER] in ON_STATUS diff --git a/homeassistant/components/jvc_projector/config_flow.py b/homeassistant/components/jvc_projector/config_flow.py index 5d9bedd7591..26131f687c2 100644 --- a/homeassistant/components/jvc_projector/config_flow.py +++ b/homeassistant/components/jvc_projector/config_flow.py @@ -5,7 +5,12 @@ from __future__ import annotations from collections.abc import Mapping from typing import Any -from jvcprojector import JvcProjector, JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector import ( + JvcProjector, + JvcProjectorAuthError, + JvcProjectorTimeoutError, + command as cmd, +) from jvcprojector.projector import DEFAULT_PORT import voluptuous as vol @@ -40,7 +45,7 @@ class JvcProjectorConfigFlow(ConfigFlow, domain=DOMAIN): mac = await get_mac_address(host, port, password) except InvalidHost: errors["base"] = "invalid_host" - except JvcProjectorConnectError: + except JvcProjectorTimeoutError: errors["base"] = "cannot_connect" except JvcProjectorAuthError: errors["base"] = "invalid_auth" @@ -91,7 +96,7 @@ class JvcProjectorConfigFlow(ConfigFlow, domain=DOMAIN): try: await get_mac_address(host, port, password) - except JvcProjectorConnectError: + except JvcProjectorTimeoutError: errors["base"] = "cannot_connect" except JvcProjectorAuthError: errors["base"] = "invalid_auth" @@ -115,7 +120,7 @@ async def get_mac_address(host: str, port: int, password: str | None) -> str: """Get device mac address for config flow.""" device = JvcProjector(host, port=port, password=password) try: - await device.connect(True) + await device.connect() + return await device.get(cmd.MacAddress) finally: await device.disconnect() - return device.mac diff --git a/homeassistant/components/jvc_projector/const.py b/homeassistant/components/jvc_projector/const.py index e15aa93bfa5..d0dbd1f73f8 100644 --- a/homeassistant/components/jvc_projector/const.py +++ b/homeassistant/components/jvc_projector/const.py @@ -3,3 +3,7 @@ NAME = "JVC Projector" DOMAIN = "jvc_projector" MANUFACTURER = "JVC" + +POWER = "power" +INPUT = "input" +SOURCE = "source" diff --git a/homeassistant/components/jvc_projector/coordinator.py b/homeassistant/components/jvc_projector/coordinator.py index db97b05f980..58ca14a3738 100644 --- a/homeassistant/components/jvc_projector/coordinator.py +++ b/homeassistant/components/jvc_projector/coordinator.py @@ -4,22 +4,21 @@ from __future__ import annotations from datetime import timedelta import logging -from typing import Any +from typing import TYPE_CHECKING, Any from jvcprojector import ( JvcProjector, JvcProjectorAuthError, - JvcProjectorConnectError, - const, + JvcProjectorTimeoutError, + command as cmd, ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed -from homeassistant.helpers.device_registry import format_mac from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import NAME +from .const import INPUT, NAME, POWER _LOGGER = logging.getLogger(__name__) @@ -46,26 +45,33 @@ class JvcProjectorDataUpdateCoordinator(DataUpdateCoordinator[dict[str, str]]): update_interval=INTERVAL_SLOW, ) - self.device = device - self.unique_id = format_mac(device.mac) + self.device: JvcProjector = device + + if TYPE_CHECKING: + assert config_entry.unique_id is not None + self.unique_id = config_entry.unique_id async def _async_update_data(self) -> dict[str, Any]: """Get the latest state data.""" + state: dict[str, str | None] = { + POWER: None, + INPUT: None, + } + try: - state = await self.device.get_state() - except JvcProjectorConnectError as err: + state[POWER] = await self.device.get(cmd.Power) + + if state[POWER] == cmd.Power.ON: + state[INPUT] = await self.device.get(cmd.Input) + + except JvcProjectorTimeoutError as err: raise UpdateFailed(f"Unable to connect to {self.device.host}") from err except JvcProjectorAuthError as err: raise ConfigEntryAuthFailed("Password authentication failed") from err - old_interval = self.update_interval - - if state[const.POWER] != const.STANDBY: + if state[POWER] != cmd.Power.STANDBY: self.update_interval = INTERVAL_FAST else: self.update_interval = INTERVAL_SLOW - if self.update_interval != old_interval: - _LOGGER.debug("Changed update interval to %s", self.update_interval) - return state diff --git a/homeassistant/components/jvc_projector/entity.py b/homeassistant/components/jvc_projector/entity.py index a88fba03cb0..317bc5ce654 100644 --- a/homeassistant/components/jvc_projector/entity.py +++ b/homeassistant/components/jvc_projector/entity.py @@ -26,7 +26,7 @@ class JvcProjectorEntity(CoordinatorEntity[JvcProjectorDataUpdateCoordinator]): self._attr_unique_id = coordinator.unique_id self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, coordinator.unique_id)}, + identifiers={(DOMAIN, self._attr_unique_id)}, name=NAME, model=self.device.model, manufacturer=MANUFACTURER, diff --git a/homeassistant/components/jvc_projector/manifest.json b/homeassistant/components/jvc_projector/manifest.json index 530373850eb..46f04de7094 100644 --- a/homeassistant/components/jvc_projector/manifest.json +++ b/homeassistant/components/jvc_projector/manifest.json @@ -7,5 +7,5 @@ "integration_type": "device", "iot_class": "local_polling", "loggers": ["jvcprojector"], - "requirements": ["pyjvcprojector==1.1.3"] + "requirements": ["pyjvcprojector==2.0.0"] } diff --git a/homeassistant/components/jvc_projector/remote.py b/homeassistant/components/jvc_projector/remote.py index 22855a9f801..f2e436f41d0 100644 --- a/homeassistant/components/jvc_projector/remote.py +++ b/homeassistant/components/jvc_projector/remote.py @@ -7,54 +7,62 @@ from collections.abc import Iterable import logging from typing import Any -from jvcprojector import const +from jvcprojector import command as cmd from homeassistant.components.remote import RemoteEntity from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from .const import POWER from .coordinator import JVCConfigEntry from .entity import JvcProjectorEntity -COMMANDS = { - "menu": const.REMOTE_MENU, - "up": const.REMOTE_UP, - "down": const.REMOTE_DOWN, - "left": const.REMOTE_LEFT, - "right": const.REMOTE_RIGHT, - "ok": const.REMOTE_OK, - "back": const.REMOTE_BACK, - "mpc": const.REMOTE_MPC, - "hide": const.REMOTE_HIDE, - "info": const.REMOTE_INFO, - "input": const.REMOTE_INPUT, - "cmd": const.REMOTE_CMD, - "advanced_menu": const.REMOTE_ADVANCED_MENU, - "picture_mode": const.REMOTE_PICTURE_MODE, - "color_profile": const.REMOTE_COLOR_PROFILE, - "lens_control": const.REMOTE_LENS_CONTROL, - "setting_memory": const.REMOTE_SETTING_MEMORY, - "gamma_settings": const.REMOTE_GAMMA_SETTINGS, - "hdmi_1": const.REMOTE_HDMI_1, - "hdmi_2": const.REMOTE_HDMI_2, - "mode_1": const.REMOTE_MODE_1, - "mode_2": const.REMOTE_MODE_2, - "mode_3": const.REMOTE_MODE_3, - "mode_4": const.REMOTE_MODE_4, - "mode_5": const.REMOTE_MODE_5, - "mode_6": const.REMOTE_MODE_6, - "mode_7": const.REMOTE_MODE_7, - "mode_8": const.REMOTE_MODE_8, - "mode_9": const.REMOTE_MODE_9, - "mode_10": const.REMOTE_MODE_10, - "lens_ap": const.REMOTE_LENS_AP, - "gamma": const.REMOTE_GAMMA, - "color_temp": const.REMOTE_COLOR_TEMP, - "natural": const.REMOTE_NATURAL, - "cinema": const.REMOTE_CINEMA, - "anamo": const.REMOTE_ANAMO, - "3d_format": const.REMOTE_3D_FORMAT, +COMMANDS: list[str] = [ + cmd.Remote.MENU, + cmd.Remote.UP, + cmd.Remote.DOWN, + cmd.Remote.LEFT, + cmd.Remote.RIGHT, + cmd.Remote.OK, + cmd.Remote.BACK, + cmd.Remote.MPC, + cmd.Remote.HIDE, + cmd.Remote.INFO, + cmd.Remote.INPUT, + cmd.Remote.CMD, + cmd.Remote.ADVANCED_MENU, + cmd.Remote.PICTURE_MODE, + cmd.Remote.COLOR_PROFILE, + cmd.Remote.LENS_CONTROL, + cmd.Remote.SETTING_MEMORY, + cmd.Remote.GAMMA_SETTINGS, + cmd.Remote.HDMI1, + cmd.Remote.HDMI2, + cmd.Remote.MODE_1, + cmd.Remote.MODE_2, + cmd.Remote.MODE_3, + cmd.Remote.MODE_4, + cmd.Remote.MODE_5, + cmd.Remote.MODE_6, + cmd.Remote.MODE_7, + cmd.Remote.MODE_8, + cmd.Remote.MODE_9, + cmd.Remote.MODE_10, + cmd.Remote.GAMMA, + cmd.Remote.NATURAL, + cmd.Remote.CINEMA, + cmd.Remote.COLOR_TEMP, + cmd.Remote.ANAMORPHIC, + cmd.Remote.LENS_APERTURE, + cmd.Remote.V3D_FORMAT, +] + +RENAMED_COMMANDS: dict[str, str] = { + "anamo": cmd.Remote.ANAMORPHIC, + "lens_ap": cmd.Remote.LENS_APERTURE, + "hdmi1": cmd.Remote.HDMI1, + "hdmi2": cmd.Remote.HDMI2, } _LOGGER = logging.getLogger(__name__) @@ -77,25 +85,34 @@ class JvcProjectorRemote(JvcProjectorEntity, RemoteEntity): @property def is_on(self) -> bool: - """Return True if entity is on.""" - return self.coordinator.data["power"] in [const.ON, const.WARMING] + """Return True if the entity is on.""" + return self.coordinator.data[POWER] in (cmd.Power.ON, cmd.Power.WARMING) async def async_turn_on(self, **kwargs: Any) -> None: """Turn the device on.""" - await self.device.power_on() + await self.device.set(cmd.Power, cmd.Power.ON) await asyncio.sleep(1) await self.coordinator.async_refresh() async def async_turn_off(self, **kwargs: Any) -> None: """Turn the device off.""" - await self.device.power_off() + await self.device.set(cmd.Power, cmd.Power.OFF) await asyncio.sleep(1) await self.coordinator.async_refresh() async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None: """Send a remote command to the device.""" - for cmd in command: - if cmd not in COMMANDS: - raise HomeAssistantError(f"{cmd} is not a known command") - _LOGGER.debug("Sending command '%s'", cmd) - await self.device.remote(COMMANDS[cmd]) + for send_command in command: + # Legacy name replace + if send_command in RENAMED_COMMANDS: + send_command = RENAMED_COMMANDS[send_command] + + # Legacy name fixup + if "_" in send_command: + send_command = send_command.replace("_", "-") + + if send_command not in COMMANDS: + raise HomeAssistantError(f"{send_command} is not a known command") + + _LOGGER.debug("Sending command '%s'", send_command) + await self.device.remote(send_command) diff --git a/homeassistant/components/jvc_projector/select.py b/homeassistant/components/jvc_projector/select.py index b83695609cb..861c2846a0a 100644 --- a/homeassistant/components/jvc_projector/select.py +++ b/homeassistant/components/jvc_projector/select.py @@ -6,7 +6,7 @@ from collections.abc import Awaitable, Callable from dataclasses import dataclass from typing import Final -from jvcprojector import JvcProjector, const +from jvcprojector import JvcProjector, command as cmd from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.core import HomeAssistant @@ -23,16 +23,12 @@ class JvcProjectorSelectDescription(SelectEntityDescription): command: Callable[[JvcProjector, str], Awaitable[None]] -OPTIONS: Final[dict[str, dict[str, str]]] = { - "input": {const.HDMI1: const.REMOTE_HDMI_1, const.HDMI2: const.REMOTE_HDMI_2} -} - SELECTS: Final[list[JvcProjectorSelectDescription]] = [ JvcProjectorSelectDescription( key="input", translation_key="input", - options=list(OPTIONS["input"]), - command=lambda device, option: device.remote(OPTIONS["input"][option]), + options=[cmd.Input.HDMI1, cmd.Input.HDMI2], + command=lambda device, option: device.set(cmd.Input, option), ) ] diff --git a/homeassistant/components/jvc_projector/sensor.py b/homeassistant/components/jvc_projector/sensor.py index 7a7799bc4ee..dd0c16e6fff 100644 --- a/homeassistant/components/jvc_projector/sensor.py +++ b/homeassistant/components/jvc_projector/sensor.py @@ -2,7 +2,7 @@ from __future__ import annotations -from jvcprojector import const +from jvcprojector import command as cmd from homeassistant.components.sensor import ( SensorDeviceClass, @@ -23,11 +23,11 @@ JVC_SENSORS = ( device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, options=[ - const.STANDBY, - const.ON, - const.WARMING, - const.COOLING, - const.ERROR, + cmd.Power.STANDBY, + cmd.Power.ON, + cmd.Power.WARMING, + cmd.Power.COOLING, + cmd.Power.ERROR, ], ), ) diff --git a/homeassistant/components/jvc_projector/strings.json b/homeassistant/components/jvc_projector/strings.json index a536b2f282a..89c54ce5f2c 100644 --- a/homeassistant/components/jvc_projector/strings.json +++ b/homeassistant/components/jvc_projector/strings.json @@ -35,7 +35,7 @@ }, "entity": { "binary_sensor": { - "jvc_power": { + "power": { "name": "[%key:component::binary_sensor::entity_component::power::name%]" } }, @@ -50,7 +50,7 @@ }, "sensor": { "jvc_power_status": { - "name": "Power status", + "name": "Status", "state": { "cooling": "Cooling", "error": "[%key:common::state::error%]", diff --git a/homeassistant/components/keba/notify.py b/homeassistant/components/keba/notify.py index 5358ba32ff9..3495e46649c 100644 --- a/homeassistant/components/keba/notify.py +++ b/homeassistant/components/keba/notify.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import Any + from homeassistant.components.notify import ATTR_DATA, BaseNotificationService from homeassistant.core import HomeAssistant from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -27,7 +29,7 @@ class KebaNotificationService(BaseNotificationService): """Initialize the service.""" self._client = client - async def async_send_message(self, message="", **kwargs): + async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send the message.""" text = message.replace(" ", "$") # Will be translated back by the display diff --git a/homeassistant/components/knx/__init__.py b/homeassistant/components/knx/__init__.py index ead846735c9..cf91107852a 100644 --- a/homeassistant/components/knx/__init__.py +++ b/homeassistant/components/knx/__init__.py @@ -27,7 +27,7 @@ from .const import ( SUPPORTED_PLATFORMS_UI, SUPPORTED_PLATFORMS_YAML, ) -from .expose import create_knx_exposure +from .expose import create_combined_knx_exposure from .knx_module import KNXModule from .project import STORAGE_KEY as PROJECT_STORAGE_KEY from .schema import ( @@ -121,10 +121,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[KNX_MODULE_KEY] = knx_module if CONF_KNX_EXPOSE in config: - for expose_config in config[CONF_KNX_EXPOSE]: - knx_module.exposures.append( - create_knx_exposure(hass, knx_module.xknx, expose_config) - ) + knx_module.yaml_exposures.extend( + create_combined_knx_exposure(hass, knx_module.xknx, config[CONF_KNX_EXPOSE]) + ) + configured_platforms_yaml = { platform for platform in SUPPORTED_PLATFORMS_YAML if platform in config } @@ -149,7 +149,9 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # if not loaded directly return return True - for exposure in knx_module.exposures: + for exposure in knx_module.yaml_exposures: + exposure.async_remove() + for exposure in knx_module.service_exposures.values(): exposure.async_remove() configured_platforms_yaml = { diff --git a/homeassistant/components/knx/expose.py b/homeassistant/components/knx/expose.py index 0a42b6018ba..e8d44385e42 100644 --- a/homeassistant/components/knx/expose.py +++ b/homeassistant/components/knx/expose.py @@ -2,14 +2,22 @@ from __future__ import annotations -from collections.abc import Callable +from asyncio import TaskGroup +from collections.abc import Callable, Iterable +from dataclasses import dataclass import logging +from typing import Any from xknx import XKNX from xknx.devices import DateDevice, DateTimeDevice, ExposeSensor, TimeDevice -from xknx.dpt import DPTNumeric, DPTString +from xknx.dpt import DPTBase, DPTNumeric, DPTString +from xknx.dpt.dpt_1 import DPT1BitEnum, DPTSwitch from xknx.exceptions import ConversionError -from xknx.remote_value import RemoteValueSensor +from xknx.telegram.address import ( + GroupAddress, + InternalGroupAddress, + parse_device_group_address, +) from homeassistant.const import ( CONF_ENTITY_ID, @@ -41,79 +49,159 @@ _LOGGER = logging.getLogger(__name__) @callback def create_knx_exposure( hass: HomeAssistant, xknx: XKNX, config: ConfigType -) -> KNXExposeSensor | KNXExposeTime: - """Create exposures from config.""" - +) -> KnxExposeEntity | KnxExposeTime: + """Create single exposure.""" expose_type = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE] - - exposure: KNXExposeSensor | KNXExposeTime + exposure: KnxExposeEntity | KnxExposeTime if ( isinstance(expose_type, str) and expose_type.lower() in ExposeSchema.EXPOSE_TIME_TYPES ): - exposure = KNXExposeTime( + exposure = KnxExposeTime( xknx=xknx, config=config, ) else: - exposure = KNXExposeSensor( - hass, + exposure = KnxExposeEntity( + hass=hass, xknx=xknx, - config=config, + entity_id=config[CONF_ENTITY_ID], + options=(_yaml_config_to_expose_options(config),), ) exposure.async_register() return exposure -class KNXExposeSensor: - """Object to Expose Home Assistant entity to KNX bus.""" +@callback +def create_combined_knx_exposure( + hass: HomeAssistant, xknx: XKNX, configs: list[ConfigType] +) -> list[KnxExposeEntity | KnxExposeTime]: + """Create exposures from YAML config combined by entity_id.""" + exposures: list[KnxExposeEntity | KnxExposeTime] = [] + entity_exposure_map: dict[str, list[KnxExposeOptions]] = {} + + for config in configs: + value_type = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE] + if value_type.lower() in ExposeSchema.EXPOSE_TIME_TYPES: + time_exposure = KnxExposeTime( + xknx=xknx, + config=config, + ) + time_exposure.async_register() + exposures.append(time_exposure) + continue + + entity_id = config[CONF_ENTITY_ID] + option = _yaml_config_to_expose_options(config) + entity_exposure_map.setdefault(entity_id, []).append(option) + + for entity_id, options in entity_exposure_map.items(): + entity_exposure = KnxExposeEntity( + hass=hass, + xknx=xknx, + entity_id=entity_id, + options=options, + ) + entity_exposure.async_register() + exposures.append(entity_exposure) + return exposures + + +@dataclass(slots=True) +class KnxExposeOptions: + """Options for KNX Expose.""" + + attribute: str | None + group_address: GroupAddress | InternalGroupAddress + dpt: type[DPTBase] + respond_to_read: bool + cooldown: float + default: Any | None + value_template: Template | None + + +def _yaml_config_to_expose_options(config: ConfigType) -> KnxExposeOptions: + """Convert single yaml expose config to KnxExposeOptions.""" + value_type = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE] + dpt: type[DPTBase] + if value_type == "binary": + # HA yaml expose flag for DPT-1 (no explicit DPT 1 definitions in xknx back then) + dpt = DPTSwitch + else: + dpt = DPTBase.parse_transcoder(config[ExposeSchema.CONF_KNX_EXPOSE_TYPE]) # type: ignore[assignment] # checked by schema validation + ga = parse_device_group_address(config[KNX_ADDRESS]) + return KnxExposeOptions( + attribute=config.get(ExposeSchema.CONF_KNX_EXPOSE_ATTRIBUTE), + group_address=ga, + dpt=dpt, + respond_to_read=config[CONF_RESPOND_TO_READ], + cooldown=config[ExposeSchema.CONF_KNX_EXPOSE_COOLDOWN], + default=config.get(ExposeSchema.CONF_KNX_EXPOSE_DEFAULT), + value_template=config.get(CONF_VALUE_TEMPLATE), + ) + + +class KnxExposeEntity: + """Expose Home Assistant entity values to KNX bus.""" def __init__( self, hass: HomeAssistant, xknx: XKNX, - config: ConfigType, + entity_id: str, + options: Iterable[KnxExposeOptions], ) -> None: - """Initialize of Expose class.""" + """Initialize KnxExposeEntity class.""" self.hass = hass self.xknx = xknx - - self.entity_id: str = config[CONF_ENTITY_ID] - self.expose_attribute: str | None = config.get( - ExposeSchema.CONF_KNX_EXPOSE_ATTRIBUTE - ) - self.expose_default = config.get(ExposeSchema.CONF_KNX_EXPOSE_DEFAULT) - self.expose_type: int | str = config[ExposeSchema.CONF_KNX_EXPOSE_TYPE] - self.value_template: Template | None = config.get(CONF_VALUE_TEMPLATE) + self.entity_id = entity_id self._remove_listener: Callable[[], None] | None = None - self.device: ExposeSensor = ExposeSensor( - xknx=self.xknx, - name=f"{self.entity_id}__{self.expose_attribute or 'state'}", - group_address=config[KNX_ADDRESS], - respond_to_read=config[CONF_RESPOND_TO_READ], - value_type=self.expose_type, - cooldown=config[ExposeSchema.CONF_KNX_EXPOSE_COOLDOWN], + self._exposures = tuple( + ( + option, + ExposeSensor( + xknx=self.xknx, + name=f"{self.entity_id} {option.attribute or 'state'}", + group_address=option.group_address, + respond_to_read=option.respond_to_read, + value_type=option.dpt, + cooldown=option.cooldown, + ), + ) + for option in options ) + @property + def name(self) -> str: + """Return name of the expose entity.""" + expose_names = [opt.attribute or "state" for opt, _ in self._exposures] + return f"{self.entity_id}__{'__'.join(expose_names)}" + @callback def async_register(self) -> None: - """Register listener.""" + """Register listener and XKNX devices.""" self._remove_listener = async_track_state_change_event( self.hass, [self.entity_id], self._async_entity_changed ) - self.xknx.devices.async_add(self.device) + for _option, xknx_expose in self._exposures: + self.xknx.devices.async_add(xknx_expose) self._init_expose_state() @callback def _init_expose_state(self) -> None: - """Initialize state of the exposure.""" + """Initialize state of all exposures.""" init_state = self.hass.states.get(self.entity_id) - state_value = self._get_expose_value(init_state) - try: - self.device.sensor_value.value = state_value - except ConversionError: - _LOGGER.exception("Error during sending of expose sensor value") + for option, xknx_expose in self._exposures: + state_value = self._get_expose_value(init_state, option) + try: + xknx_expose.sensor_value.value = state_value + except ConversionError: + _LOGGER.exception( + "Error setting value %s for expose sensor %s", + state_value, + xknx_expose.name, + ) @callback def async_remove(self) -> None: @@ -121,53 +209,57 @@ class KNXExposeSensor: if self._remove_listener is not None: self._remove_listener() self._remove_listener = None - self.xknx.devices.async_remove(self.device) + for _option, xknx_expose in self._exposures: + self.xknx.devices.async_remove(xknx_expose) - def _get_expose_value(self, state: State | None) -> bool | int | float | str | None: - """Extract value from state.""" + def _get_expose_value( + self, state: State | None, option: KnxExposeOptions + ) -> bool | int | float | str | None: + """Extract value from state for a specific option.""" if state is None or state.state in (STATE_UNKNOWN, STATE_UNAVAILABLE): - if self.expose_default is None: + if option.default is None: return None - value = self.expose_default - elif self.expose_attribute is not None: - _attr = state.attributes.get(self.expose_attribute) - value = _attr if _attr is not None else self.expose_default + value = option.default + elif option.attribute is not None: + _attr = state.attributes.get(option.attribute) + value = _attr if _attr is not None else option.default else: value = state.state - if self.value_template is not None: + if option.value_template is not None: try: - value = self.value_template.async_render_with_possible_json_value( + value = option.value_template.async_render_with_possible_json_value( value, error_value=None ) except (TemplateError, TypeError, ValueError) as err: _LOGGER.warning( - "Error rendering value template for KNX expose %s %s: %s", - self.device.name, - self.value_template.template, + "Error rendering value template for KNX expose %s %s %s: %s", + self.entity_id, + option.attribute or "state", + option.value_template.template, err, ) return None - if self.expose_type == "binary": + if issubclass(option.dpt, DPT1BitEnum): if value in (1, STATE_ON, "True"): return True if value in (0, STATE_OFF, "False"): return False - if value is not None and ( - isinstance(self.device.sensor_value, RemoteValueSensor) - ): + + # Handle numeric and string DPT conversions + if value is not None: try: - if issubclass(self.device.sensor_value.dpt_class, DPTNumeric): + if issubclass(option.dpt, DPTNumeric): return float(value) - if issubclass(self.device.sensor_value.dpt_class, DPTString): + if issubclass(option.dpt, DPTString): # DPT 16.000 only allows up to 14 Bytes return str(value)[:14] except (ValueError, TypeError) as err: _LOGGER.warning( 'Could not expose %s %s value "%s" to KNX: Conversion failed: %s', self.entity_id, - self.expose_attribute or "state", + option.attribute or "state", value, err, ) @@ -175,32 +267,31 @@ class KNXExposeSensor: return value # type: ignore[no-any-return] async def _async_entity_changed(self, event: Event[EventStateChangedData]) -> None: - """Handle entity change.""" + """Handle entity change for all options.""" new_state = event.data["new_state"] - if (new_value := self._get_expose_value(new_state)) is None: - return - old_state = event.data["old_state"] - # don't use default value for comparison on first state change (old_state is None) - old_value = self._get_expose_value(old_state) if old_state is not None else None - # don't send same value sequentially - if new_value != old_value: - await self._async_set_knx_value(new_value) + async with TaskGroup() as tg: + for option, xknx_expose in self._exposures: + expose_value = self._get_expose_value(new_state, option) + if expose_value is None: + continue + tg.create_task(self._async_set_knx_value(xknx_expose, expose_value)) - async def _async_set_knx_value(self, value: StateType) -> None: + async def _async_set_knx_value( + self, xknx_expose: ExposeSensor, value: StateType + ) -> None: """Set new value on xknx ExposeSensor.""" try: - await self.device.set(value) + await xknx_expose.set(value, skip_unchanged=True) except ConversionError as err: _LOGGER.warning( - 'Could not expose %s %s value "%s" to KNX: %s', - self.entity_id, - self.expose_attribute or "state", + 'Could not expose %s value "%s" to KNX: %s', + xknx_expose.name, value, err, ) -class KNXExposeTime: +class KnxExposeTime: """Object to Expose Time/Date object to KNX bus.""" def __init__(self, xknx: XKNX, config: ConfigType) -> None: @@ -222,6 +313,11 @@ class KNXExposeTime: group_address=config[KNX_ADDRESS], ) + @property + def name(self) -> str: + """Return name of the time expose object.""" + return f"expose_{self.device.name}" + @callback def async_register(self) -> None: """Register listener.""" diff --git a/homeassistant/components/knx/knx_module.py b/homeassistant/components/knx/knx_module.py index 42c14eae2a8..33e08badf51 100644 --- a/homeassistant/components/knx/knx_module.py +++ b/homeassistant/components/knx/knx_module.py @@ -54,7 +54,7 @@ from .const import ( TELEGRAM_LOG_DEFAULT, ) from .device import KNXInterfaceDevice -from .expose import KNXExposeSensor, KNXExposeTime +from .expose import KnxExposeEntity, KnxExposeTime from .project import KNXProject from .repairs import data_secure_group_key_issue_dispatcher from .storage.config_store import KNXConfigStore @@ -73,8 +73,8 @@ class KNXModule: self.hass = hass self.config_yaml = config self.connected = False - self.exposures: list[KNXExposeSensor | KNXExposeTime] = [] - self.service_exposures: dict[str, KNXExposeSensor | KNXExposeTime] = {} + self.yaml_exposures: list[KnxExposeEntity | KnxExposeTime] = [] + self.service_exposures: dict[str, KnxExposeEntity | KnxExposeTime] = {} self.entry = entry self.project = KNXProject(hass=hass, entry=entry) diff --git a/homeassistant/components/knx/manifest.json b/homeassistant/components/knx/manifest.json index 5f5862d9219..6e4b25e3b8e 100644 --- a/homeassistant/components/knx/manifest.json +++ b/homeassistant/components/knx/manifest.json @@ -11,9 +11,9 @@ "loggers": ["xknx", "xknxproject"], "quality_scale": "platinum", "requirements": [ - "xknx==3.13.0", + "xknx==3.14.0", "xknxproject==3.8.2", - "knx-frontend==2025.12.30.151231" + "knx-frontend==2026.1.15.112308" ], "single_config_entry": true } diff --git a/homeassistant/components/knx/services.py b/homeassistant/components/knx/services.py index ebb01e0ef28..0e6798e1584 100644 --- a/homeassistant/components/knx/services.py +++ b/homeassistant/components/knx/services.py @@ -193,7 +193,7 @@ async def service_exposure_register_modify(call: ServiceCall) -> None: " for '%s' - %s" ), group_address, - replaced_exposure.device.name, + replaced_exposure.name, ) replaced_exposure.async_remove() exposure = create_knx_exposure(knx_module.hass, knx_module.xknx, call.data) @@ -201,7 +201,7 @@ async def service_exposure_register_modify(call: ServiceCall) -> None: _LOGGER.debug( "Service exposure_register registered exposure for '%s' - %s", group_address, - exposure.device.name, + exposure.name, ) diff --git a/homeassistant/components/kodi/notify.py b/homeassistant/components/kodi/notify.py index 8360f74ce24..49e326334b9 100644 --- a/homeassistant/components/kodi/notify.py +++ b/homeassistant/components/kodi/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import aiohttp import jsonrpc_async @@ -93,7 +94,7 @@ class KodiNotificationService(BaseNotificationService): self._server = jsonrpc_async.Server(self._url, **kwargs) - async def async_send_message(self, message="", **kwargs): + async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to Kodi.""" try: data = kwargs.get(ATTR_DATA) or {} diff --git a/homeassistant/components/kostal_plenticore/manifest.json b/homeassistant/components/kostal_plenticore/manifest.json index 7bdbb7f703c..af97ddd037b 100644 --- a/homeassistant/components/kostal_plenticore/manifest.json +++ b/homeassistant/components/kostal_plenticore/manifest.json @@ -7,5 +7,5 @@ "integration_type": "device", "iot_class": "local_polling", "loggers": ["kostal"], - "requirements": ["pykoplenti==1.3.0"] + "requirements": ["pykoplenti==1.5.0"] } diff --git a/homeassistant/components/labs/__init__.py b/homeassistant/components/labs/__init__.py index 73bee604450..485d7f8c878 100644 --- a/homeassistant/components/labs/__init__.py +++ b/homeassistant/components/labs/__init__.py @@ -18,7 +18,11 @@ from homeassistant.helpers.typing import ConfigType from homeassistant.loader import async_get_custom_components from .const import DOMAIN, LABS_DATA, STORAGE_KEY, STORAGE_VERSION -from .helpers import async_is_preview_feature_enabled, async_listen +from .helpers import ( + async_is_preview_feature_enabled, + async_listen, + async_update_preview_feature, +) from .models import ( EventLabsUpdatedData, LabPreviewFeature, @@ -37,6 +41,7 @@ __all__ = [ "EventLabsUpdatedData", "async_is_preview_feature_enabled", "async_listen", + "async_update_preview_feature", ] diff --git a/homeassistant/components/labs/helpers.py b/homeassistant/components/labs/helpers.py index 3b9ce94b4ad..85430724bef 100644 --- a/homeassistant/components/labs/helpers.py +++ b/homeassistant/components/labs/helpers.py @@ -61,3 +61,32 @@ def async_listen( listener() return hass.bus.async_listen(EVENT_LABS_UPDATED, _async_feature_updated) + + +async def async_update_preview_feature( + hass: HomeAssistant, + domain: str, + preview_feature: str, + enabled: bool, +) -> None: + """Update a lab preview feature state.""" + labs_data = hass.data[LABS_DATA] + + preview_feature_id = f"{domain}.{preview_feature}" + + if preview_feature_id not in labs_data.preview_features: + raise ValueError(f"Preview feature {preview_feature_id} not found") + + if enabled: + labs_data.data.preview_feature_status.add((domain, preview_feature)) + else: + labs_data.data.preview_feature_status.discard((domain, preview_feature)) + + await labs_data.store.async_save(labs_data.data.to_store_format()) + + event_data: EventLabsUpdatedData = { + "domain": domain, + "preview_feature": preview_feature, + "enabled": enabled, + } + hass.bus.async_fire(EVENT_LABS_UPDATED, event_data) diff --git a/homeassistant/components/labs/websocket_api.py b/homeassistant/components/labs/websocket_api.py index bccfe0c53de..f1f744f8a47 100644 --- a/homeassistant/components/labs/websocket_api.py +++ b/homeassistant/components/labs/websocket_api.py @@ -8,12 +8,14 @@ import voluptuous as vol from homeassistant.components import websocket_api from homeassistant.components.backup import async_get_manager -from homeassistant.const import EVENT_LABS_UPDATED from homeassistant.core import HomeAssistant, callback from .const import LABS_DATA -from .helpers import async_is_preview_feature_enabled, async_listen -from .models import EventLabsUpdatedData +from .helpers import ( + async_is_preview_feature_enabled, + async_listen, + async_update_preview_feature, +) @callback @@ -95,19 +97,7 @@ async def websocket_update_preview_feature( ) return - if enabled: - labs_data.data.preview_feature_status.add((domain, preview_feature)) - else: - labs_data.data.preview_feature_status.discard((domain, preview_feature)) - - await labs_data.store.async_save(labs_data.data.to_store_format()) - - event_data: EventLabsUpdatedData = { - "domain": domain, - "preview_feature": preview_feature, - "enabled": enabled, - } - hass.bus.async_fire(EVENT_LABS_UPDATED, event_data) + await async_update_preview_feature(hass, domain, preview_feature, enabled) connection.send_result(msg["id"]) diff --git a/homeassistant/components/lamarzocco/number.py b/homeassistant/components/lamarzocco/number.py index 61db4deb6a2..2eee3956bba 100644 --- a/homeassistant/components/lamarzocco/number.py +++ b/homeassistant/components/lamarzocco/number.py @@ -256,6 +256,8 @@ ENTITIES: tuple[LaMarzoccoNumberEntityDescription, ...] = ( supported_fn=( lambda coordinator: coordinator.device.dashboard.model_name in (ModelName.LINEA_MINI, ModelName.LINEA_MINI_R) + and WidgetType.CM_BREW_BY_WEIGHT_DOSES + in coordinator.device.dashboard.config ), ), LaMarzoccoNumberEntityDescription( @@ -289,6 +291,8 @@ ENTITIES: tuple[LaMarzoccoNumberEntityDescription, ...] = ( supported_fn=( lambda coordinator: coordinator.device.dashboard.model_name in (ModelName.LINEA_MINI, ModelName.LINEA_MINI_R) + and WidgetType.CM_BREW_BY_WEIGHT_DOSES + in coordinator.device.dashboard.config ), ), ) diff --git a/homeassistant/components/lamarzocco/select.py b/homeassistant/components/lamarzocco/select.py index d7662b6f50d..921f6a8d50d 100644 --- a/homeassistant/components/lamarzocco/select.py +++ b/homeassistant/components/lamarzocco/select.py @@ -149,6 +149,8 @@ ENTITIES: tuple[LaMarzoccoSelectEntityDescription, ...] = ( supported_fn=( lambda coordinator: coordinator.device.dashboard.model_name in (ModelName.LINEA_MINI, ModelName.LINEA_MINI_R) + and WidgetType.CM_BREW_BY_WEIGHT_DOSES + in coordinator.device.dashboard.config ), ), ) diff --git a/homeassistant/components/lannouncer/notify.py b/homeassistant/components/lannouncer/notify.py index 983a5e7b32a..4b5f249a2f1 100644 --- a/homeassistant/components/lannouncer/notify.py +++ b/homeassistant/components/lannouncer/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations import logging import socket +from typing import Any from urllib.parse import urlencode import voluptuous as vol @@ -73,7 +74,7 @@ class LannouncerNotificationService(BaseNotificationService): self._host = host self._port = port - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to Lannouncer.""" data = kwargs.get(ATTR_DATA) if data is not None and ATTR_METHOD in data: diff --git a/homeassistant/components/lawn_mower/strings.json b/homeassistant/components/lawn_mower/strings.json index 501daf20539..0ae72cbee9d 100644 --- a/homeassistant/components/lawn_mower/strings.json +++ b/homeassistant/components/lawn_mower/strings.json @@ -41,7 +41,7 @@ "title": "Lawn mower", "triggers": { "docked": { - "description": "Triggers after one or more lawn mowers return to dock.", + "description": "Triggers after one or more lawn mowers have returned to dock.", "fields": { "behavior": { "description": "[%key:component::lawn_mower::common::trigger_behavior_description%]", diff --git a/homeassistant/components/light/condition.py b/homeassistant/components/light/condition.py index 139f9e71ebc..59fcd10c831 100644 --- a/homeassistant/components/light/condition.py +++ b/homeassistant/components/light/condition.py @@ -1,127 +1,14 @@ """Provides conditions for lights.""" -from collections.abc import Callable -from typing import TYPE_CHECKING, Any, Final, Unpack, override - -import voluptuous as vol - -from homeassistant.const import CONF_OPTIONS, CONF_TARGET, STATE_OFF, STATE_ON -from homeassistant.core import HomeAssistant, split_entity_id -from homeassistant.helpers import config_validation as cv, target -from homeassistant.helpers.condition import ( - Condition, - ConditionChecker, - ConditionCheckParams, - ConditionConfig, -) -from homeassistant.helpers.typing import ConfigType +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant +from homeassistant.helpers.condition import Condition, make_entity_state_condition from .const import DOMAIN -ATTR_BEHAVIOR: Final = "behavior" -BEHAVIOR_ANY: Final = "any" -BEHAVIOR_ALL: Final = "all" - - -STATE_CONDITION_VALID_STATES: Final = [STATE_ON, STATE_OFF] -STATE_CONDITION_OPTIONS_SCHEMA: dict[vol.Marker, Any] = { - vol.Required(ATTR_BEHAVIOR, default=BEHAVIOR_ANY): vol.In( - [BEHAVIOR_ANY, BEHAVIOR_ALL] - ), -} -STATE_CONDITION_SCHEMA = vol.Schema( - { - vol.Required(CONF_TARGET): cv.TARGET_FIELDS, - vol.Required(CONF_OPTIONS): STATE_CONDITION_OPTIONS_SCHEMA, - } -) - - -class StateConditionBase(Condition): - """State condition.""" - - @override - @classmethod - async def async_validate_config( - cls, hass: HomeAssistant, config: ConfigType - ) -> ConfigType: - """Validate config.""" - return STATE_CONDITION_SCHEMA(config) # type: ignore[no-any-return] - - def __init__( - self, hass: HomeAssistant, config: ConditionConfig, state: str - ) -> None: - """Initialize condition.""" - super().__init__(hass, config) - if TYPE_CHECKING: - assert config.target - assert config.options - self._target = config.target - self._behavior = config.options[ATTR_BEHAVIOR] - self._state = state - - @override - async def async_get_checker(self) -> ConditionChecker: - """Get the condition checker.""" - - def check_any_match_state(states: list[str]) -> bool: - """Test if any entity match the state.""" - return any(state == self._state for state in states) - - def check_all_match_state(states: list[str]) -> bool: - """Test if all entities match the state.""" - return all(state == self._state for state in states) - - matcher: Callable[[list[str]], bool] - if self._behavior == BEHAVIOR_ANY: - matcher = check_any_match_state - elif self._behavior == BEHAVIOR_ALL: - matcher = check_all_match_state - - def test_state(**kwargs: Unpack[ConditionCheckParams]) -> bool: - """Test state condition.""" - target_selection = target.TargetSelection(self._target) - targeted_entities = target.async_extract_referenced_entity_ids( - self._hass, target_selection, expand_group=False - ) - referenced_entity_ids = targeted_entities.referenced.union( - targeted_entities.indirectly_referenced - ) - light_entity_ids = { - entity_id - for entity_id in referenced_entity_ids - if split_entity_id(entity_id)[0] == DOMAIN - } - light_entity_states = [ - state.state - for entity_id in light_entity_ids - if (state := self._hass.states.get(entity_id)) - and state.state in STATE_CONDITION_VALID_STATES - ] - return matcher(light_entity_states) - - return test_state - - -class IsOnCondition(StateConditionBase): - """Is on condition.""" - - def __init__(self, hass: HomeAssistant, config: ConditionConfig) -> None: - """Initialize condition.""" - super().__init__(hass, config, STATE_ON) - - -class IsOffCondition(StateConditionBase): - """Is off condition.""" - - def __init__(self, hass: HomeAssistant, config: ConditionConfig) -> None: - """Initialize condition.""" - super().__init__(hass, config, STATE_OFF) - - CONDITIONS: dict[str, type[Condition]] = { - "is_off": IsOffCondition, - "is_on": IsOnCondition, + "is_off": make_entity_state_condition(DOMAIN, STATE_OFF), + "is_on": make_entity_state_condition(DOMAIN, STATE_ON), } diff --git a/homeassistant/components/light/conditions.yaml b/homeassistant/components/light/conditions.yaml index cfcb4748836..a35a581ffc1 100644 --- a/homeassistant/components/light/conditions.yaml +++ b/homeassistant/components/light/conditions.yaml @@ -1,18 +1,4 @@ -is_off: - target: - entity: - domain: light - fields: - behavior: - required: true - default: any - selector: - select: - translation_key: condition_behavior - options: - - all - - any -is_on: +.condition_common: &condition_common target: entity: domain: light @@ -26,3 +12,6 @@ is_on: options: - all - any + +is_off: *condition_common +is_on: *condition_common diff --git a/homeassistant/components/light/strings.json b/homeassistant/components/light/strings.json index 73807d09deb..11e5c9a5309 100644 --- a/homeassistant/components/light/strings.json +++ b/homeassistant/components/light/strings.json @@ -42,7 +42,7 @@ }, "conditions": { "is_off": { - "description": "Test if a light is off.", + "description": "Tests if one or more lights are off.", "fields": { "behavior": { "description": "[%key:component::light::common::condition_behavior_description%]", @@ -52,7 +52,7 @@ "name": "If a light is off" }, "is_on": { - "description": "Test if a light is on.", + "description": "Tests if one or more lights are on.", "fields": { "behavior": { "description": "[%key:component::light::common::condition_behavior_description%]", diff --git a/homeassistant/components/light/trigger.py b/homeassistant/components/light/trigger.py index 5a3550fc58b..2e087b00397 100644 --- a/homeassistant/components/light/trigger.py +++ b/homeassistant/components/light/trigger.py @@ -1,24 +1,47 @@ """Provides triggers for lights.""" +from typing import Any + from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant from homeassistant.helpers.trigger import ( + EntityNumericalStateAttributeChangedTriggerBase, + EntityNumericalStateAttributeCrossedThresholdTriggerBase, Trigger, - make_entity_numerical_state_attribute_changed_trigger, - make_entity_numerical_state_attribute_crossed_threshold_trigger, make_entity_target_state_trigger, ) from . import ATTR_BRIGHTNESS from .const import DOMAIN + +def _convert_uint8_to_percentage(value: Any) -> float: + """Convert a uint8 value (0-255) to a percentage (0-100).""" + return (float(value) / 255.0) * 100.0 + + +class BrightnessChangedTrigger(EntityNumericalStateAttributeChangedTriggerBase): + """Trigger for brightness changed.""" + + _domain = DOMAIN + _attribute = ATTR_BRIGHTNESS + + _converter = staticmethod(_convert_uint8_to_percentage) + + +class BrightnessCrossedThresholdTrigger( + EntityNumericalStateAttributeCrossedThresholdTriggerBase +): + """Trigger for brightness crossed threshold.""" + + _domain = DOMAIN + _attribute = ATTR_BRIGHTNESS + _converter = staticmethod(_convert_uint8_to_percentage) + + TRIGGERS: dict[str, type[Trigger]] = { - "brightness_changed": make_entity_numerical_state_attribute_changed_trigger( - DOMAIN, ATTR_BRIGHTNESS - ), - "brightness_crossed_threshold": make_entity_numerical_state_attribute_crossed_threshold_trigger( - DOMAIN, ATTR_BRIGHTNESS - ), + "brightness_changed": BrightnessChangedTrigger, + "brightness_crossed_threshold": BrightnessCrossedThresholdTrigger, "turned_off": make_entity_target_state_trigger(DOMAIN, STATE_OFF), "turned_on": make_entity_target_state_trigger(DOMAIN, STATE_ON), } diff --git a/homeassistant/components/light/triggers.yaml b/homeassistant/components/light/triggers.yaml index 75843ea1a53..e55026ced87 100644 --- a/homeassistant/components/light/triggers.yaml +++ b/homeassistant/components/light/triggers.yaml @@ -22,7 +22,10 @@ number: selector: number: + max: 100 + min: 0 mode: box + unit_of_measurement: "%" entity: selector: entity: diff --git a/homeassistant/components/llamalab_automate/notify.py b/homeassistant/components/llamalab_automate/notify.py index da13267aec3..94693d3faa0 100644 --- a/homeassistant/components/llamalab_automate/notify.py +++ b/homeassistant/components/llamalab_automate/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations from http import HTTPStatus import logging +from typing import Any import requests import voluptuous as vol @@ -56,7 +57,7 @@ class AutomateNotificationService(BaseNotificationService): self._recipient = recipient self._device = device - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" # Extract params from data dict diff --git a/homeassistant/components/london_air/sensor.py b/homeassistant/components/london_air/sensor.py index a4d34fcb2d6..b3c7535b9b7 100644 --- a/homeassistant/components/london_air/sensor.py +++ b/homeassistant/components/london_air/sensor.py @@ -27,6 +27,7 @@ SCAN_INTERVAL = timedelta(minutes=30) AUTHORITIES = [ "Barking and Dagenham", + "Barnet", "Bexley", "Brent", "Bromley", @@ -49,11 +50,13 @@ AUTHORITIES = [ "Lambeth", "Lewisham", "Merton", + "Newham", "Redbridge", "Richmond", "Southwark", "Sutton", "Tower Hamlets", + "Waltham Forest", "Wandsworth", "Westminster", ] diff --git a/homeassistant/components/london_underground/manifest.json b/homeassistant/components/london_underground/manifest.json index 1b9b8ddcbeb..15cf41ef98c 100644 --- a/homeassistant/components/london_underground/manifest.json +++ b/homeassistant/components/london_underground/manifest.json @@ -7,7 +7,6 @@ "integration_type": "service", "iot_class": "cloud_polling", "loggers": ["london_tube_status"], - "quality_scale": "legacy", "requirements": ["london-tube-status==0.5"], "single_config_entry": true } diff --git a/homeassistant/components/mailgun/notify.py b/homeassistant/components/mailgun/notify.py index b839e184810..daf5eb904ab 100644 --- a/homeassistant/components/mailgun/notify.py +++ b/homeassistant/components/mailgun/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any from pymailgunner import ( Client, @@ -91,7 +92,7 @@ class MailgunNotificationService(BaseNotificationService): return False return True - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a mail to the recipient.""" subject = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) diff --git a/homeassistant/components/mastodon/__init__.py b/homeassistant/components/mastodon/__init__.py index 531b88ac38a..8e4910d937a 100644 --- a/homeassistant/components/mastodon/__init__.py +++ b/homeassistant/components/mastodon/__init__.py @@ -28,7 +28,7 @@ from .coordinator import MastodonConfigEntry, MastodonCoordinator, MastodonData from .services import async_setup_services from .utils import construct_mastodon_username, create_mastodon_client -PLATFORMS: list[Platform] = [Platform.SENSOR] +PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR] CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN) diff --git a/homeassistant/components/mastodon/binary_sensor.py b/homeassistant/components/mastodon/binary_sensor.py new file mode 100644 index 00000000000..42400c8b238 --- /dev/null +++ b/homeassistant/components/mastodon/binary_sensor.py @@ -0,0 +1,128 @@ +"""Binary sensor platform for the Mastodon integration.""" + +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +from enum import StrEnum + +from mastodon.Mastodon import Account + +from homeassistant.components.binary_sensor import ( + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from .coordinator import MastodonConfigEntry +from .entity import MastodonEntity + +# Coordinator is used to centralize the data updates +PARALLEL_UPDATES = 0 + + +class MastodonBinarySensor(StrEnum): + """Mastodon binary sensors.""" + + BOT = "bot" + SUSPENDED = "suspended" + DISCOVERABLE = "discoverable" + LOCKED = "locked" + INDEXABLE = "indexable" + LIMITED = "limited" + MEMORIAL = "memorial" + MOVED = "moved" + + +@dataclass(frozen=True, kw_only=True) +class MastodonBinarySensorEntityDescription(BinarySensorEntityDescription): + """Mastodon binary sensor description.""" + + is_on_fn: Callable[[Account], bool | None] + + +ENTITY_DESCRIPTIONS: tuple[MastodonBinarySensorEntityDescription, ...] = ( + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.BOT, + translation_key=MastodonBinarySensor.BOT, + is_on_fn=lambda account: account.bot, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.DISCOVERABLE, + translation_key=MastodonBinarySensor.DISCOVERABLE, + is_on_fn=lambda account: account.discoverable, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.LOCKED, + translation_key=MastodonBinarySensor.LOCKED, + is_on_fn=lambda account: account.locked, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.MOVED, + translation_key=MastodonBinarySensor.MOVED, + is_on_fn=lambda account: account.moved is not None, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.INDEXABLE, + translation_key=MastodonBinarySensor.INDEXABLE, + is_on_fn=lambda account: account.indexable, + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.LIMITED, + translation_key=MastodonBinarySensor.LIMITED, + is_on_fn=lambda account: account.limited is True, + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.MEMORIAL, + translation_key=MastodonBinarySensor.MEMORIAL, + is_on_fn=lambda account: account.memorial is True, + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), + MastodonBinarySensorEntityDescription( + key=MastodonBinarySensor.SUSPENDED, + translation_key=MastodonBinarySensor.SUSPENDED, + is_on_fn=lambda account: account.suspended is True, + entity_registry_enabled_default=False, + entity_category=EntityCategory.DIAGNOSTIC, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: MastodonConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up the binary sensor platform.""" + coordinator = entry.runtime_data.coordinator + + async_add_entities( + MastodonBinarySensorEntity( + coordinator=coordinator, + entity_description=entity_description, + data=entry, + ) + for entity_description in ENTITY_DESCRIPTIONS + ) + + +class MastodonBinarySensorEntity(MastodonEntity, BinarySensorEntity): + """Mastodon binary sensor entity.""" + + entity_description: MastodonBinarySensorEntityDescription + + @property + def is_on(self) -> bool | None: + """Return true if the binary sensor is on.""" + return self.entity_description.is_on_fn(self.coordinator.data) diff --git a/homeassistant/components/mastodon/icons.json b/homeassistant/components/mastodon/icons.json index e7272c2b6f8..2ea8b34788f 100644 --- a/homeassistant/components/mastodon/icons.json +++ b/homeassistant/components/mastodon/icons.json @@ -1,5 +1,18 @@ { "entity": { + "binary_sensor": { + "bot": { "default": "mdi:robot" }, + "discoverable": { "default": "mdi:magnify-scan" }, + "indexable": { "default": "mdi:search-web" }, + "limited": { "default": "mdi:account-cancel" }, + "locked": { + "default": "mdi:account-lock", + "state": { "off": "mdi:account-lock-open" } + }, + "memorial": { "default": "mdi:candle" }, + "moved": { "default": "mdi:truck-delivery" }, + "suspended": { "default": "mdi:account-off" } + }, "sensor": { "followers": { "default": "mdi:account-multiple" diff --git a/homeassistant/components/mastodon/strings.json b/homeassistant/components/mastodon/strings.json index 93161a8129d..5c42cdefcf3 100644 --- a/homeassistant/components/mastodon/strings.json +++ b/homeassistant/components/mastodon/strings.json @@ -26,6 +26,16 @@ } }, "entity": { + "binary_sensor": { + "bot": { "name": "Bot" }, + "discoverable": { "name": "Discoverable" }, + "indexable": { "name": "Indexable" }, + "limited": { "name": "Limited" }, + "locked": { "name": "Locked" }, + "memorial": { "name": "Memorial" }, + "moved": { "name": "Moved" }, + "suspended": { "name": "Suspended" } + }, "sensor": { "followers": { "name": "Followers", diff --git a/homeassistant/components/matter/binary_sensor.py b/homeassistant/components/matter/binary_sensor.py index a3148f3719f..58c6edff070 100644 --- a/homeassistant/components/matter/binary_sensor.py +++ b/homeassistant/components/matter/binary_sensor.py @@ -489,6 +489,7 @@ DISCOVERY_SCHEMAS = [ platform=Platform.BINARY_SENSOR, entity_description=MatterBinarySensorEntityDescription( key="WindowCoveringConfigStatusOperational", + translation_key="config_status_operational", device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, # unset Operational bit from ConfigStatus bitmap means problem @@ -528,7 +529,10 @@ DISCOVERY_SCHEMAS = [ ), ), entity_class=MatterBinarySensor, - required_attributes=(clusters.Thermostat.Attributes.RemoteSensing,), + required_attributes=( + clusters.Thermostat.Attributes.RemoteSensing, + clusters.Thermostat.Attributes.OutdoorTemperature, + ), allow_multi=True, ), MatterDiscoverySchema( diff --git a/homeassistant/components/matter/number.py b/homeassistant/components/matter/number.py index a20e6b3b42a..db13c9faebb 100644 --- a/homeassistant/components/matter/number.py +++ b/homeassistant/components/matter/number.py @@ -66,8 +66,9 @@ class MatterRangeNumberEntityDescription( format_max_value: Callable[[float], float] = lambda x: x # command: a custom callback to create the command to send to the device - # the callback's argument will be the index of the selected list value - command: Callable[[int], ClusterCommand] + # the callback's argument will be the converted device value from ha_to_device + # if omitted the command will just be a write_attribute command to the primary attribute + command: Callable[[int], ClusterCommand] | None = None class MatterNumber(MatterEntity, NumberEntity): @@ -99,9 +100,15 @@ class MatterRangeNumber(MatterEntity, NumberEntity): async def async_set_native_value(self, value: float) -> None: """Update the current value.""" send_value = self.entity_description.ha_to_device(value) - # custom command defined to set the new value - await self.send_device_command( - self.entity_description.command(send_value), + if self.entity_description.command: + # custom command defined to set the new value + await self.send_device_command( + self.entity_description.command(send_value), + ) + return + # regular write attribute to set the new value + await self.write_attribute( + value=send_value, ) @callback @@ -253,6 +260,30 @@ DISCOVERY_SCHEMAS = [ entity_class=MatterNumber, required_attributes=(custom_clusters.EveCluster.Attributes.Altitude,), ), + MatterDiscoverySchema( + platform=Platform.NUMBER, + entity_description=MatterRangeNumberEntityDescription( + key="ThermostatOccupiedSetback", + entity_category=EntityCategory.CONFIG, + translation_key="occupied_setback", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_to_ha=lambda x: None if x is None else x / 10, + ha_to_device=lambda x: round(x * 10), + format_min_value=lambda x: x / 10, + format_max_value=lambda x: x / 10, + min_attribute=clusters.Thermostat.Attributes.OccupiedSetbackMin, + max_attribute=clusters.Thermostat.Attributes.OccupiedSetbackMax, + native_step=0.5, + mode=NumberMode.BOX, + ), + entity_class=MatterRangeNumber, + required_attributes=( + clusters.Thermostat.Attributes.OccupiedSetback, + clusters.Thermostat.Attributes.OccupiedSetbackMin, + clusters.Thermostat.Attributes.OccupiedSetbackMax, + ), + featuremap_contains=(clusters.Thermostat.Bitmaps.Feature.kSetback), + ), MatterDiscoverySchema( platform=Platform.NUMBER, entity_description=MatterNumberEntityDescription( diff --git a/homeassistant/components/matter/select.py b/homeassistant/components/matter/select.py index cc7041965fe..ff72dcd58b5 100644 --- a/homeassistant/components/matter/select.py +++ b/homeassistant/components/matter/select.py @@ -642,6 +642,7 @@ DISCOVERY_SCHEMAS = [ list_attribute=clusters.DoorLock.Attributes.SupportedOperatingModes, device_to_ha=DOOR_LOCK_OPERATING_MODE_MAP.get, ha_to_device=DOOR_LOCK_OPERATING_MODE_MAP_REVERSE.get, + entity_category=EntityCategory.CONFIG, ), entity_class=MatterDoorLockOperatingModeSelectEntity, required_attributes=( diff --git a/homeassistant/components/matter/sensor.py b/homeassistant/components/matter/sensor.py index 0832675744e..3077ff10cc6 100644 --- a/homeassistant/components/matter/sensor.py +++ b/homeassistant/components/matter/sensor.py @@ -442,6 +442,9 @@ DISCOVERY_SCHEMAS = [ key="PowerSourceBatVoltage", translation_key="battery_voltage", native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT, + # Battery voltages are low-voltage diagnostics; use 2 decimals in volts + # to provide finer granularity than mains-level voltage sensors. + suggested_display_precision=2, suggested_unit_of_measurement=UnitOfElectricPotential.VOLT, device_class=SensorDeviceClass.VOLTAGE, entity_category=EntityCategory.DIAGNOSTIC, diff --git a/homeassistant/components/matter/strings.json b/homeassistant/components/matter/strings.json index 9fa3425c4e4..abaaf46ef42 100644 --- a/homeassistant/components/matter/strings.json +++ b/homeassistant/components/matter/strings.json @@ -56,6 +56,9 @@ "boost_state": { "name": "Boost state" }, + "config_status_operational": { + "name": "Configuration status" + }, "dishwasher_alarm_inflow": { "name": "Inflow alarm" }, @@ -217,6 +220,9 @@ "led_indicator_intensity_on": { "name": "LED on intensity" }, + "occupied_setback": { + "name": "Occupied setback" + }, "off_transition_time": { "name": "Off transition time" }, diff --git a/homeassistant/components/maxcube/climate.py b/homeassistant/components/maxcube/climate.py index 65b1795023f..c20a855d656 100644 --- a/homeassistant/components/maxcube/climate.py +++ b/homeassistant/components/maxcube/climate.py @@ -192,7 +192,7 @@ class MaxCubeClimate(ClimateEntity): self._set_target(None, temp) @property - def preset_mode(self): + def preset_mode(self) -> str: """Return the current preset mode.""" if self._device.mode == MAX_DEVICE_MODE_MANUAL: if self._device.target_temperature == self._device.comfort_temperature: diff --git a/homeassistant/components/mealie/config_flow.py b/homeassistant/components/mealie/config_flow.py index a88347894f5..f0f294e45cb 100644 --- a/homeassistant/components/mealie/config_flow.py +++ b/homeassistant/components/mealie/config_flow.py @@ -50,7 +50,7 @@ class MealieConfigFlow(ConfigFlow, domain=DOMAIN): """Check connection to the Mealie API.""" assert self.host is not None - if "/hassio/ingress/" in self.host: + if "/app/" in self.host: return {"base": "ingress_url"}, None client = MealieClient( diff --git a/homeassistant/components/mealie/manifest.json b/homeassistant/components/mealie/manifest.json index 5e090a6af73..21fe1b11197 100644 --- a/homeassistant/components/mealie/manifest.json +++ b/homeassistant/components/mealie/manifest.json @@ -7,5 +7,5 @@ "integration_type": "service", "iot_class": "local_polling", "quality_scale": "platinum", - "requirements": ["aiomealie==1.1.1"] + "requirements": ["aiomealie==1.2.0"] } diff --git a/homeassistant/components/melcloud/__init__.py b/homeassistant/components/melcloud/__init__.py index d78807106c1..34ac5aea1cf 100644 --- a/homeassistant/components/melcloud/__init__.py +++ b/homeassistant/components/melcloud/__init__.py @@ -4,45 +4,70 @@ from __future__ import annotations import asyncio from datetime import timedelta -import logging -from typing import Any +from http import HTTPStatus from aiohttp import ClientConnectionError, ClientResponseError -from pymelcloud import Device, get_devices -from pymelcloud.atw_device import Zone +from pymelcloud import get_devices from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_TOKEN, Platform from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady +from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.helpers import device_registry as dr from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo -from homeassistant.util import Throttle +from homeassistant.helpers.update_coordinator import UpdateFailed -from .const import DOMAIN - -_LOGGER = logging.getLogger(__name__) - -MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15) +from .coordinator import MelCloudConfigEntry, MelCloudDeviceUpdateCoordinator PLATFORMS = [Platform.CLIMATE, Platform.SENSOR, Platform.WATER_HEATER] -type MelCloudConfigEntry = ConfigEntry[dict[str, list[MelCloudDevice]]] - async def async_setup_entry(hass: HomeAssistant, entry: MelCloudConfigEntry) -> bool: """Establish connection with MELCloud.""" - conf = entry.data try: - mel_devices = await mel_devices_setup(hass, conf[CONF_TOKEN]) + async with asyncio.timeout(10): + all_devices = await get_devices( + token=entry.data[CONF_TOKEN], + session=async_get_clientsession(hass), + conf_update_interval=timedelta(minutes=30), + device_set_debounce=timedelta(seconds=2), + ) except ClientResponseError as ex: - if isinstance(ex, ClientResponseError) and ex.code == 401: + if ex.status in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN): raise ConfigEntryAuthFailed from ex - raise ConfigEntryNotReady from ex + if ex.status == HTTPStatus.TOO_MANY_REQUESTS: + raise UpdateFailed( + "MELCloud rate limit exceeded. Your account may be temporarily blocked" + ) from ex + raise UpdateFailed(f"Error communicating with MELCloud: {ex}") from ex except (TimeoutError, ClientConnectionError) as ex: - raise ConfigEntryNotReady from ex + raise UpdateFailed(f"Error communicating with MELCloud: {ex}") from ex - entry.runtime_data = mel_devices + # Create per-device coordinators + coordinators: dict[str, list[MelCloudDeviceUpdateCoordinator]] = {} + device_registry = dr.async_get(hass) + for device_type, devices in all_devices.items(): + # Build coordinators for this device_type + coordinators[device_type] = [ + MelCloudDeviceUpdateCoordinator(hass, device, entry) for device in devices + ] + + # Perform initial refreshes concurrently + await asyncio.gather( + *( + coordinator.async_config_entry_first_refresh() + for coordinator in coordinators[device_type] + ) + ) + + # Register parent devices so zone entities can reference via_device + for coordinator in coordinators[device_type]: + device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + **coordinator.device_info, + ) + + entry.runtime_data = coordinators await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True @@ -50,90 +75,3 @@ async def async_setup_entry(hass: HomeAssistant, entry: MelCloudConfigEntry) -> async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: """Unload a config entry.""" return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS) - - -class MelCloudDevice: - """MELCloud Device instance.""" - - def __init__(self, device: Device) -> None: - """Construct a device wrapper.""" - self.device = device - self.name = device.name - self._available = True - - @Throttle(MIN_TIME_BETWEEN_UPDATES) - async def async_update(self, **kwargs): - """Pull the latest data from MELCloud.""" - try: - await self.device.update() - self._available = True - except ClientConnectionError: - _LOGGER.warning("Connection failed for %s", self.name) - self._available = False - - async def async_set(self, properties: dict[str, Any]): - """Write state changes to the MELCloud API.""" - try: - await self.device.set(properties) - self._available = True - except ClientConnectionError: - _LOGGER.warning("Connection failed for %s", self.name) - self._available = False - - @property - def available(self) -> bool: - """Return True if entity is available.""" - return self._available - - @property - def device_id(self): - """Return device ID.""" - return self.device.device_id - - @property - def building_id(self): - """Return building ID of the device.""" - return self.device.building_id - - @property - def device_info(self) -> DeviceInfo: - """Return a device description for device registry.""" - model = None - if (unit_infos := self.device.units) is not None: - model = ", ".join([x["model"] for x in unit_infos if x["model"]]) - return DeviceInfo( - connections={(CONNECTION_NETWORK_MAC, self.device.mac)}, - identifiers={(DOMAIN, f"{self.device.mac}-{self.device.serial}")}, - manufacturer="Mitsubishi Electric", - model=model, - name=self.name, - ) - - def zone_device_info(self, zone: Zone) -> DeviceInfo: - """Return a zone device description for device registry.""" - dev = self.device - return DeviceInfo( - identifiers={(DOMAIN, f"{dev.mac}-{dev.serial}-{zone.zone_index}")}, - manufacturer="Mitsubishi Electric", - model="ATW zone device", - name=f"{self.name} {zone.name}", - via_device=(DOMAIN, f"{dev.mac}-{dev.serial}"), - ) - - -async def mel_devices_setup( - hass: HomeAssistant, token: str -) -> dict[str, list[MelCloudDevice]]: - """Query connected devices from MELCloud.""" - session = async_get_clientsession(hass) - async with asyncio.timeout(10): - all_devices = await get_devices( - token, - session, - conf_update_interval=timedelta(minutes=30), - device_set_debounce=timedelta(seconds=2), - ) - wrapped_devices: dict[str, list[MelCloudDevice]] = {} - for device_type, devices in all_devices.items(): - wrapped_devices[device_type] = [MelCloudDevice(device) for device in devices] - return wrapped_devices diff --git a/homeassistant/components/melcloud/climate.py b/homeassistant/components/melcloud/climate.py index 47a96d03f06..488268a3295 100644 --- a/homeassistant/components/melcloud/climate.py +++ b/homeassistant/components/melcloud/climate.py @@ -2,7 +2,6 @@ from __future__ import annotations -from datetime import timedelta from typing import Any, cast from pymelcloud import DEVICE_TYPE_ATA, DEVICE_TYPE_ATW, AtaDevice, AtwDevice @@ -29,7 +28,6 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from . import MelCloudConfigEntry, MelCloudDevice from .const import ( ATTR_STATUS, ATTR_VANE_HORIZONTAL, @@ -40,9 +38,8 @@ from .const import ( SERVICE_SET_VANE_HORIZONTAL, SERVICE_SET_VANE_VERTICAL, ) - -SCAN_INTERVAL = timedelta(seconds=60) - +from .coordinator import MelCloudConfigEntry, MelCloudDeviceUpdateCoordinator +from .entity import MelCloudEntity ATA_HVAC_MODE_LOOKUP = { ata.OPERATION_MODE_HEAT: HVACMode.HEAT, @@ -74,27 +71,24 @@ ATW_ZONE_HVAC_ACTION_LOOKUP = { async def async_setup_entry( - hass: HomeAssistant, + _hass: HomeAssistant, entry: MelCloudConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up MelCloud device climate based on config_entry.""" - mel_devices = entry.runtime_data + coordinators = entry.runtime_data entities: list[AtaDeviceClimate | AtwDeviceZoneClimate] = [ - AtaDeviceClimate(mel_device, mel_device.device) - for mel_device in mel_devices[DEVICE_TYPE_ATA] + AtaDeviceClimate(coordinator, coordinator.device) + for coordinator in coordinators.get(DEVICE_TYPE_ATA, []) ] entities.extend( [ - AtwDeviceZoneClimate(mel_device, mel_device.device, zone) - for mel_device in mel_devices[DEVICE_TYPE_ATW] - for zone in mel_device.device.zones + AtwDeviceZoneClimate(coordinator, coordinator.device, zone) + for coordinator in coordinators.get(DEVICE_TYPE_ATW, []) + for zone in coordinator.device.zones ] ) - async_add_entities( - entities, - True, - ) + async_add_entities(entities) platform = entity_platform.async_get_current_platform() platform.async_register_entity_service( @@ -109,21 +103,19 @@ async def async_setup_entry( ) -class MelCloudClimate(ClimateEntity): +class MelCloudClimate(MelCloudEntity, ClimateEntity): """Base climate device.""" _attr_temperature_unit = UnitOfTemperature.CELSIUS - _attr_has_entity_name = True _attr_name = None - def __init__(self, device: MelCloudDevice) -> None: + def __init__( + self, + coordinator: MelCloudDeviceUpdateCoordinator, + ) -> None: """Initialize the climate.""" - self.api = device - self._base_device = self.api.device - - async def async_update(self) -> None: - """Update state from MELCloud.""" - await self.api.async_update() + super().__init__(coordinator) + self._base_device = self.coordinator.device @property def target_temperature_step(self) -> float | None: @@ -142,26 +134,29 @@ class AtaDeviceClimate(MelCloudClimate): | ClimateEntityFeature.TURN_ON ) - def __init__(self, device: MelCloudDevice, ata_device: AtaDevice) -> None: + def __init__( + self, + coordinator: MelCloudDeviceUpdateCoordinator, + ata_device: AtaDevice, + ) -> None: """Initialize the climate.""" - super().__init__(device) + super().__init__(coordinator) self._device = ata_device - self._attr_unique_id = f"{self.api.device.serial}-{self.api.device.mac}" - self._attr_device_info = self.api.device_info + self._attr_unique_id = ( + f"{self.coordinator.device.serial}-{self.coordinator.device.mac}" + ) + self._attr_device_info = self.coordinator.device_info - async def async_added_to_hass(self) -> None: - """When entity is added to hass.""" - await super().async_added_to_hass() - - # We can only check for vane_horizontal once we fetch the device data from the cloud + # Add horizontal swing if device supports it if self._device.vane_horizontal: self._attr_supported_features |= ClimateEntityFeature.SWING_HORIZONTAL_MODE @property def extra_state_attributes(self) -> dict[str, Any] | None: """Return the optional state attributes with device specific additions.""" - attr = {} + attr: dict[str, Any] = {} + attr.update(self.coordinator.extra_attributes) if vane_horizontal := self._device.vane_horizontal: attr.update( @@ -208,7 +203,7 @@ class AtaDeviceClimate(MelCloudClimate): """Set new target hvac mode.""" set_dict: dict[str, Any] = {} self._apply_set_hvac_mode(hvac_mode, set_dict) - await self._device.set(set_dict) + await self.coordinator.async_set(set_dict) @property def hvac_modes(self) -> list[HVACMode]: @@ -241,7 +236,7 @@ class AtaDeviceClimate(MelCloudClimate): set_dict["target_temperature"] = kwargs.get(ATTR_TEMPERATURE) if set_dict: - await self._device.set(set_dict) + await self.coordinator.async_set(set_dict) @property def fan_mode(self) -> str | None: @@ -250,7 +245,7 @@ class AtaDeviceClimate(MelCloudClimate): async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" - await self._device.set({"fan_speed": fan_mode}) + await self.coordinator.async_set({"fan_speed": fan_mode}) @property def fan_modes(self) -> list[str] | None: @@ -264,7 +259,7 @@ class AtaDeviceClimate(MelCloudClimate): f"Invalid horizontal vane position {position}. Valid positions:" f" [{self._device.vane_horizontal_positions}]." ) - await self._device.set({ata.PROPERTY_VANE_HORIZONTAL: position}) + await self.coordinator.async_set({ata.PROPERTY_VANE_HORIZONTAL: position}) async def async_set_vane_vertical(self, position: str) -> None: """Set vertical vane position.""" @@ -273,7 +268,7 @@ class AtaDeviceClimate(MelCloudClimate): f"Invalid vertical vane position {position}. Valid positions:" f" [{self._device.vane_vertical_positions}]." ) - await self._device.set({ata.PROPERTY_VANE_VERTICAL: position}) + await self.coordinator.async_set({ata.PROPERTY_VANE_VERTICAL: position}) @property def swing_mode(self) -> str | None: @@ -305,11 +300,11 @@ class AtaDeviceClimate(MelCloudClimate): async def async_turn_on(self) -> None: """Turn the entity on.""" - await self._device.set({"power": True}) + await self.coordinator.async_set({"power": True}) async def async_turn_off(self) -> None: """Turn the entity off.""" - await self._device.set({"power": False}) + await self.coordinator.async_set({"power": False}) @property def min_temp(self) -> float: @@ -338,15 +333,18 @@ class AtwDeviceZoneClimate(MelCloudClimate): _attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE def __init__( - self, device: MelCloudDevice, atw_device: AtwDevice, atw_zone: Zone + self, + coordinator: MelCloudDeviceUpdateCoordinator, + atw_device: AtwDevice, + atw_zone: Zone, ) -> None: """Initialize the climate.""" - super().__init__(device) + super().__init__(coordinator) self._device = atw_device self._zone = atw_zone - self._attr_unique_id = f"{self.api.device.serial}-{atw_zone.zone_index}" - self._attr_device_info = self.api.zone_device_info(atw_zone) + self._attr_unique_id = f"{self.coordinator.device.serial}-{atw_zone.zone_index}" + self._attr_device_info = self.coordinator.zone_device_info(atw_zone) @property def extra_state_attributes(self) -> dict[str, Any]: @@ -360,15 +358,16 @@ class AtwDeviceZoneClimate(MelCloudClimate): @property def hvac_mode(self) -> HVACMode: """Return hvac operation ie. heat, cool mode.""" - mode = self._zone.operation_mode - if not self._device.power or mode is None: + # Use zone status (heat/cool/idle) not operation_mode (heat-thermostat/etc.) + status = self._zone.status + if not self._device.power or status is None: return HVACMode.OFF - return ATW_ZONE_HVAC_MODE_LOOKUP.get(mode, HVACMode.OFF) + return ATW_ZONE_HVAC_MODE_LOOKUP.get(status, HVACMode.OFF) async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set new target hvac mode.""" if hvac_mode == HVACMode.OFF: - await self._device.set({"power": False}) + await self.coordinator.async_set({"power": False}) return operation_mode = ATW_ZONE_HVAC_MODE_REVERSE_LOOKUP.get(hvac_mode) @@ -381,7 +380,7 @@ class AtwDeviceZoneClimate(MelCloudClimate): props = {PROPERTY_ZONE_2_OPERATION_MODE: operation_mode} if self.hvac_mode == HVACMode.OFF: props["power"] = True - await self._device.set(props) + await self.coordinator.async_set(props) @property def hvac_modes(self) -> list[HVACMode]: @@ -410,3 +409,4 @@ class AtwDeviceZoneClimate(MelCloudClimate): await self._zone.set_target_temperature( kwargs.get(ATTR_TEMPERATURE, self.target_temperature) ) + await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/melcloud/config_flow.py b/homeassistant/components/melcloud/config_flow.py index d2c9d67f29a..87fe14dce81 100644 --- a/homeassistant/components/melcloud/config_flow.py +++ b/homeassistant/components/melcloud/config_flow.py @@ -5,7 +5,6 @@ from __future__ import annotations import asyncio from collections.abc import Mapping from http import HTTPStatus -import logging from typing import Any from aiohttp import ClientError, ClientResponseError @@ -18,8 +17,6 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession from .const import DOMAIN -_LOGGER = logging.getLogger(__name__) - class FlowHandler(ConfigFlow, domain=DOMAIN): """Handle a config flow.""" @@ -37,8 +34,7 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): async def _create_client( self, username: str, - *, - password: str | None = None, + password: str, token: str | None = None, ) -> ConfigFlowResult: """Create client.""" @@ -46,13 +42,13 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): async with asyncio.timeout(10): if (acquired_token := token) is None: acquired_token = await pymelcloud.login( - username, - password, - async_get_clientsession(self.hass), + email=username, + password=password, + session=async_get_clientsession(self.hass), ) await pymelcloud.get_devices( - acquired_token, - async_get_clientsession(self.hass), + token=acquired_token, + session=async_get_clientsession(self.hass), ) except ClientResponseError as err: if err.status in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN): @@ -60,6 +56,10 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): return self.async_abort(reason="cannot_connect") except (TimeoutError, ClientError): return self.async_abort(reason="cannot_connect") + except AttributeError: + # python-melcloud library bug: login() raises AttributeError on invalid + # credentials when API response doesn't contain expected "LoginData" key + return self.async_abort(reason="invalid_auth") return await self._create_entry(username, acquired_token) @@ -74,8 +74,9 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): {vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str} ), ) - username = user_input[CONF_USERNAME] - return await self._create_client(username, password=user_input[CONF_PASSWORD]) + return await self._create_client( + username=user_input[CONF_USERNAME], password=user_input[CONF_PASSWORD] + ) async def async_step_reauth( self, entry_data: Mapping[str, Any] @@ -114,9 +115,9 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): try: async with asyncio.timeout(10): acquired_token = await pymelcloud.login( - user_input[CONF_USERNAME], - user_input[CONF_PASSWORD], - async_get_clientsession(self.hass), + email=user_input[CONF_USERNAME], + password=user_input[CONF_PASSWORD], + session=async_get_clientsession(self.hass), ) except (ClientResponseError, AttributeError) as err: if ( @@ -130,10 +131,7 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): errors["base"] = "invalid_auth" else: errors["base"] = "cannot_connect" - except ( - TimeoutError, - ClientError, - ): + except (TimeoutError, ClientError): errors["base"] = "cannot_connect" return acquired_token, errors @@ -151,9 +149,9 @@ class FlowHandler(ConfigFlow, domain=DOMAIN): try: async with asyncio.timeout(10): acquired_token = await pymelcloud.login( - user_input[CONF_USERNAME], - user_input[CONF_PASSWORD], - async_get_clientsession(self.hass), + email=user_input[CONF_USERNAME], + password=user_input[CONF_PASSWORD], + session=async_get_clientsession(self.hass), ) except (ClientResponseError, AttributeError) as err: if ( diff --git a/homeassistant/components/melcloud/coordinator.py b/homeassistant/components/melcloud/coordinator.py new file mode 100644 index 00000000000..3b4c6f57f5b --- /dev/null +++ b/homeassistant/components/melcloud/coordinator.py @@ -0,0 +1,193 @@ +"""DataUpdateCoordinator for the MELCloud integration.""" + +from __future__ import annotations + +from datetime import timedelta +import logging +from typing import Any + +from aiohttp import ClientConnectionError, ClientResponseError +from pymelcloud import Device +from pymelcloud.atw_device import Zone + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ConfigEntryAuthFailed +from homeassistant.helpers.debounce import Debouncer +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +# Delay before refreshing after a state change to allow device to process +# and avoid race conditions with rapid sequential changes +REQUEST_REFRESH_DELAY = 1.5 + +# Default update interval in minutes (matches upstream Throttle value) +DEFAULT_UPDATE_INTERVAL = 15 + +# Retry interval in seconds for transient failures +RETRY_INTERVAL_SECONDS = 30 + +# Number of consecutive failures before marking device unavailable +MAX_CONSECUTIVE_FAILURES = 3 + + +class MelCloudDeviceUpdateCoordinator(DataUpdateCoordinator[None]): + """Per-device coordinator for MELCloud data updates.""" + + def __init__( + self, + hass: HomeAssistant, + device: Device, + config_entry: ConfigEntry, + ) -> None: + """Initialize the per-device coordinator.""" + self.device = device + self.device_available = True + self._consecutive_failures = 0 + + super().__init__( + hass, + _LOGGER, + config_entry=config_entry, + name=f"{DOMAIN}_{device.name}", + update_interval=timedelta(minutes=DEFAULT_UPDATE_INTERVAL), + always_update=True, + request_refresh_debouncer=Debouncer( + hass, + _LOGGER, + cooldown=REQUEST_REFRESH_DELAY, + immediate=False, + ), + ) + + @property + def extra_attributes(self) -> dict[str, Any]: + """Return extra device attributes.""" + data: dict[str, Any] = { + "device_id": self.device.device_id, + "serial": self.device.serial, + "mac": self.device.mac, + } + if (unit_infos := self.device.units) is not None: + for i, unit in enumerate(unit_infos[:2]): + data[f"unit_{i}_model"] = unit.get("model") + data[f"unit_{i}_serial"] = unit.get("serial") + return data + + @property + def device_id(self) -> str: + """Return device ID.""" + return self.device.device_id + + @property + def building_id(self) -> str: + """Return building ID of the device.""" + return self.device.building_id + + @property + def device_info(self) -> DeviceInfo: + """Return a device description for device registry.""" + model = None + if (unit_infos := self.device.units) is not None: + model = ", ".join([x["model"] for x in unit_infos if x["model"]]) + return DeviceInfo( + connections={(CONNECTION_NETWORK_MAC, self.device.mac)}, + identifiers={(DOMAIN, f"{self.device.mac}-{self.device.serial}")}, + manufacturer="Mitsubishi Electric", + model=model, + name=self.device.name, + ) + + def zone_device_info(self, zone: Zone) -> DeviceInfo: + """Return a zone device description for device registry.""" + dev = self.device + return DeviceInfo( + identifiers={(DOMAIN, f"{dev.mac}-{dev.serial}-{zone.zone_index}")}, + manufacturer="Mitsubishi Electric", + model="ATW zone device", + name=f"{self.device.name} {zone.name}", + via_device=(DOMAIN, f"{dev.mac}-{dev.serial}"), + ) + + async def _async_update_data(self) -> None: + """Fetch data for this specific device from MELCloud.""" + try: + await self.device.update() + # Success - reset failure counter and restore normal interval + if self._consecutive_failures > 0: + _LOGGER.info( + "Connection restored for %s after %d failed attempt(s)", + self.device.name, + self._consecutive_failures, + ) + self._consecutive_failures = 0 + self.update_interval = timedelta(minutes=DEFAULT_UPDATE_INTERVAL) + self.device_available = True + except ClientResponseError as ex: + if ex.status in (401, 403): + raise ConfigEntryAuthFailed from ex + if ex.status == 429: + _LOGGER.error( + "MELCloud rate limit exceeded for %s. Your account may be " + "temporarily blocked", + self.device.name, + ) + # Rate limit - mark unavailable immediately + self.device_available = False + raise UpdateFailed( + f"Rate limit exceeded for {self.device.name}" + ) from ex + # Other HTTP errors - use retry logic + self._handle_failure(f"Error updating {self.device.name}: {ex}", ex) + except ClientConnectionError as ex: + self._handle_failure(f"Connection failed for {self.device.name}: {ex}", ex) + + def _handle_failure(self, message: str, exception: Exception | None = None) -> None: + """Handle a connection failure with retry logic. + + For transient failures, entities remain available with their last known + values for up to MAX_CONSECUTIVE_FAILURES attempts. During retries, the + update interval is shortened to RETRY_INTERVAL_SECONDS for faster recovery. + After the threshold is reached, entities are marked unavailable. + """ + self._consecutive_failures += 1 + + if self._consecutive_failures < MAX_CONSECUTIVE_FAILURES: + # Keep entities available with cached data, use shorter retry interval + _LOGGER.warning( + "%s (attempt %d/%d, retrying in %ds)", + message, + self._consecutive_failures, + MAX_CONSECUTIVE_FAILURES, + RETRY_INTERVAL_SECONDS, + ) + self.update_interval = timedelta(seconds=RETRY_INTERVAL_SECONDS) + else: + # Threshold reached - mark unavailable and restore normal interval + _LOGGER.warning( + "%s (attempt %d/%d, marking unavailable)", + message, + self._consecutive_failures, + MAX_CONSECUTIVE_FAILURES, + ) + self.device_available = False + self.update_interval = timedelta(minutes=DEFAULT_UPDATE_INTERVAL) + raise UpdateFailed(message) from exception + + async def async_set(self, properties: dict[str, Any]) -> None: + """Write state changes to the MELCloud API.""" + try: + await self.device.set(properties) + self.device_available = True + except ClientConnectionError: + _LOGGER.warning("Connection failed for %s", self.device.name) + self.device_available = False + + await self.async_request_refresh() + + +type MelCloudConfigEntry = ConfigEntry[dict[str, list[MelCloudDeviceUpdateCoordinator]]] diff --git a/homeassistant/components/melcloud/diagnostics.py b/homeassistant/components/melcloud/diagnostics.py index 4606b7c25e5..c601f886470 100644 --- a/homeassistant/components/melcloud/diagnostics.py +++ b/homeassistant/components/melcloud/diagnostics.py @@ -9,7 +9,7 @@ from homeassistant.const import CONF_TOKEN, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from . import MelCloudConfigEntry +from .coordinator import MelCloudConfigEntry TO_REDACT = { CONF_USERNAME, diff --git a/homeassistant/components/melcloud/entity.py b/homeassistant/components/melcloud/entity.py new file mode 100644 index 00000000000..b0d9b839481 --- /dev/null +++ b/homeassistant/components/melcloud/entity.py @@ -0,0 +1,18 @@ +"""Base entity for MELCloud integration.""" + +from __future__ import annotations + +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .coordinator import MelCloudDeviceUpdateCoordinator + + +class MelCloudEntity(CoordinatorEntity[MelCloudDeviceUpdateCoordinator]): + """Base class for MELCloud entities.""" + + _attr_has_entity_name = True + + @property + def available(self) -> bool: + """Return True if entity is available.""" + return super().available and self.coordinator.device_available diff --git a/homeassistant/components/melcloud/manifest.json b/homeassistant/components/melcloud/manifest.json index c68b9cab3c3..b683ee6671a 100644 --- a/homeassistant/components/melcloud/manifest.json +++ b/homeassistant/components/melcloud/manifest.json @@ -6,6 +6,6 @@ "documentation": "https://www.home-assistant.io/integrations/melcloud", "integration_type": "device", "iot_class": "cloud_polling", - "loggers": ["pymelcloud"], + "loggers": ["melcloud"], "requirements": ["python-melcloud==0.1.2"] } diff --git a/homeassistant/components/melcloud/sensor.py b/homeassistant/components/melcloud/sensor.py index 1d36c74f27c..f88150ac6cd 100644 --- a/homeassistant/components/melcloud/sensor.py +++ b/homeassistant/components/melcloud/sensor.py @@ -19,7 +19,8 @@ from homeassistant.const import UnitOfEnergy, UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from . import MelCloudConfigEntry, MelCloudDevice +from .coordinator import MelCloudConfigEntry, MelCloudDeviceUpdateCoordinator +from .entity import MelCloudEntity @dataclasses.dataclass(frozen=True, kw_only=True) @@ -111,70 +112,67 @@ ATW_ZONE_SENSORS: tuple[MelcloudSensorEntityDescription, ...] = ( async def async_setup_entry( - hass: HomeAssistant, + _hass: HomeAssistant, entry: MelCloudConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up MELCloud device sensors based on config_entry.""" - mel_devices = entry.runtime_data + coordinators = entry.runtime_data entities: list[MelDeviceSensor] = [ - MelDeviceSensor(mel_device, description) + MelDeviceSensor(coordinator, description) for description in ATA_SENSORS - for mel_device in mel_devices[DEVICE_TYPE_ATA] - if description.enabled(mel_device) + for coordinator in coordinators.get(DEVICE_TYPE_ATA, []) + if description.enabled(coordinator) ] + [ - MelDeviceSensor(mel_device, description) + MelDeviceSensor(coordinator, description) for description in ATW_SENSORS - for mel_device in mel_devices[DEVICE_TYPE_ATW] - if description.enabled(mel_device) + for coordinator in coordinators.get(DEVICE_TYPE_ATW, []) + if description.enabled(coordinator) ] entities.extend( [ - AtwZoneSensor(mel_device, zone, description) - for mel_device in mel_devices[DEVICE_TYPE_ATW] - for zone in mel_device.device.zones + AtwZoneSensor(coordinator, zone, description) + for coordinator in coordinators.get(DEVICE_TYPE_ATW, []) + for zone in coordinator.device.zones for description in ATW_ZONE_SENSORS if description.enabled(zone) ] ) - async_add_entities(entities, True) + async_add_entities(entities) -class MelDeviceSensor(SensorEntity): +class MelDeviceSensor(MelCloudEntity, SensorEntity): """Representation of a Sensor.""" entity_description: MelcloudSensorEntityDescription - _attr_has_entity_name = True def __init__( self, - api: MelCloudDevice, + coordinator: MelCloudDeviceUpdateCoordinator, description: MelcloudSensorEntityDescription, ) -> None: """Initialize the sensor.""" - self._api = api + super().__init__(coordinator) self.entity_description = description - self._attr_unique_id = f"{api.device.serial}-{api.device.mac}-{description.key}" - self._attr_device_info = api.device_info + self._attr_unique_id = ( + f"{coordinator.device.serial}-{coordinator.device.mac}-{description.key}" + ) + self._attr_device_info = coordinator.device_info @property def native_value(self) -> float | None: """Return the state of the sensor.""" - return self.entity_description.value_fn(self._api) - - async def async_update(self) -> None: - """Retrieve latest state.""" - await self._api.async_update() + return self.entity_description.value_fn(self.coordinator) class AtwZoneSensor(MelDeviceSensor): - """Air-to-Air device sensor.""" + """Air-to-Water zone sensor.""" def __init__( self, - api: MelCloudDevice, + coordinator: MelCloudDeviceUpdateCoordinator, zone: Zone, description: MelcloudSensorEntityDescription, ) -> None: @@ -184,9 +182,9 @@ class AtwZoneSensor(MelDeviceSensor): description, key=f"{description.key}-zone-{zone.zone_index}", ) - super().__init__(api, description) + super().__init__(coordinator, description) - self._attr_device_info = api.zone_device_info(zone) + self._attr_device_info = coordinator.zone_device_info(zone) self._zone = zone @property diff --git a/homeassistant/components/melcloud/strings.json b/homeassistant/components/melcloud/strings.json index b670530283f..c8a1d14c214 100644 --- a/homeassistant/components/melcloud/strings.json +++ b/homeassistant/components/melcloud/strings.json @@ -43,6 +43,9 @@ }, "entity": { "sensor": { + "energy_consumed": { + "name": "Energy consumed" + }, "flow_temperature": { "name": "Flow temperature" }, diff --git a/homeassistant/components/melcloud/water_heater.py b/homeassistant/components/melcloud/water_heater.py index f006df2478e..6b91ef4a353 100644 --- a/homeassistant/components/melcloud/water_heater.py +++ b/homeassistant/components/melcloud/water_heater.py @@ -21,27 +21,27 @@ from homeassistant.const import UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from . import MelCloudConfigEntry, MelCloudDevice from .const import ATTR_STATUS +from .coordinator import MelCloudConfigEntry, MelCloudDeviceUpdateCoordinator +from .entity import MelCloudEntity async def async_setup_entry( - hass: HomeAssistant, + _hass: HomeAssistant, entry: MelCloudConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up MelCloud device climate based on config_entry.""" - mel_devices = entry.runtime_data + coordinators = entry.runtime_data async_add_entities( [ - AtwWaterHeater(mel_device, mel_device.device) - for mel_device in mel_devices[DEVICE_TYPE_ATW] - ], - True, + AtwWaterHeater(coordinator, coordinator.device) + for coordinator in coordinators.get(DEVICE_TYPE_ATW, []) + ] ) -class AtwWaterHeater(WaterHeaterEntity): +class AtwWaterHeater(MelCloudEntity, WaterHeaterEntity): """Air-to-Water water heater.""" _attr_supported_features = ( @@ -49,27 +49,26 @@ class AtwWaterHeater(WaterHeaterEntity): | WaterHeaterEntityFeature.ON_OFF | WaterHeaterEntityFeature.OPERATION_MODE ) - _attr_has_entity_name = True _attr_name = None - def __init__(self, api: MelCloudDevice, device: AtwDevice) -> None: + def __init__( + self, + coordinator: MelCloudDeviceUpdateCoordinator, + device: AtwDevice, + ) -> None: """Initialize water heater device.""" - self._api = api + super().__init__(coordinator) self._device = device - self._attr_unique_id = api.device.serial - self._attr_device_info = api.device_info + self._attr_unique_id = coordinator.device.serial + self._attr_device_info = coordinator.device_info - async def async_update(self) -> None: - """Update state from MELCloud.""" - await self._api.async_update() - - async def async_turn_on(self, **kwargs: Any) -> None: + async def async_turn_on(self, **_kwargs: Any) -> None: """Turn the entity on.""" - await self._device.set({PROPERTY_POWER: True}) + await self.coordinator.async_set({PROPERTY_POWER: True}) - async def async_turn_off(self, **kwargs: Any) -> None: + async def async_turn_off(self, **_kwargs: Any) -> None: """Turn the entity off.""" - await self._device.set({PROPERTY_POWER: False}) + await self.coordinator.async_set({PROPERTY_POWER: False}) @property def extra_state_attributes(self) -> dict[str, Any] | None: @@ -103,7 +102,7 @@ class AtwWaterHeater(WaterHeaterEntity): async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" - await self._device.set( + await self.coordinator.async_set( { PROPERTY_TARGET_TANK_TEMPERATURE: kwargs.get( "temperature", self.target_temperature @@ -113,7 +112,7 @@ class AtwWaterHeater(WaterHeaterEntity): async def async_set_operation_mode(self, operation_mode: str) -> None: """Set new target operation mode.""" - await self._device.set({PROPERTY_OPERATION_MODE: operation_mode}) + await self.coordinator.async_set({PROPERTY_OPERATION_MODE: operation_mode}) @property def min_temp(self) -> float: diff --git a/homeassistant/components/message_bird/notify.py b/homeassistant/components/message_bird/notify.py index c5cbe695243..4d4ffdc814e 100644 --- a/homeassistant/components/message_bird/notify.py +++ b/homeassistant/components/message_bird/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import messagebird from messagebird.client import ErrorException @@ -55,7 +56,7 @@ class MessageBirdNotificationService(BaseNotificationService): self.sender = sender self.client = client - def send_message(self, message=None, **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a specified target.""" if not (targets := kwargs.get(ATTR_TARGET)): _LOGGER.error("No target specified") diff --git a/homeassistant/components/mfi/sensor.py b/homeassistant/components/mfi/sensor.py index f666e2d614a..b46d876cd51 100644 --- a/homeassistant/components/mfi/sensor.py +++ b/homeassistant/components/mfi/sensor.py @@ -4,7 +4,7 @@ from __future__ import annotations import logging -from mficlient.client import FailedToLogin, MFiClient +from mficlient.client import FailedToLogin, MFiClient, Port as MFiPort import requests import voluptuous as vol @@ -12,6 +12,7 @@ from homeassistant.components.sensor import ( PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA, SensorDeviceClass, SensorEntity, + StateType, ) from homeassistant.const import ( CONF_HOST, @@ -64,24 +65,29 @@ def setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up mFi sensors.""" - host = config.get(CONF_HOST) - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - use_tls = config.get(CONF_SSL) - verify_tls = config.get(CONF_VERIFY_SSL) + host: str = config[CONF_HOST] + username: str = config[CONF_USERNAME] + password: str = config[CONF_PASSWORD] + use_tls: bool = config[CONF_SSL] + verify_tls: bool = config[CONF_VERIFY_SSL] default_port = 6443 if use_tls else 6080 - port = int(config.get(CONF_PORT, default_port)) + network_port: int = config.get(CONF_PORT, default_port) try: client = MFiClient( - host, username, password, port=port, use_tls=use_tls, verify=verify_tls + host, + username, + password, + port=network_port, + use_tls=use_tls, + verify=verify_tls, ) except (FailedToLogin, requests.exceptions.ConnectionError) as ex: _LOGGER.error("Unable to connect to mFi: %s", str(ex)) return add_entities( - MfiSensor(port, hass) + MfiSensor(port) for device in client.get_devices() for port in device.ports.values() if port.model in SENSOR_MODELS @@ -91,18 +97,17 @@ def setup_platform( class MfiSensor(SensorEntity): """Representation of a mFi sensor.""" - def __init__(self, port, hass): + def __init__(self, port: MFiPort) -> None: """Initialize the sensor.""" self._port = port - self._hass = hass @property - def name(self): + def name(self) -> str: """Return the name of the sensor.""" return self._port.label @property - def native_value(self): + def native_value(self) -> StateType: """Return the state of the sensor.""" try: tag = self._port.tag @@ -116,7 +121,7 @@ class MfiSensor(SensorEntity): return round(self._port.value, digits) @property - def device_class(self): + def device_class(self) -> SensorDeviceClass | None: """Return the device class of the sensor.""" try: tag = self._port.tag @@ -129,7 +134,7 @@ class MfiSensor(SensorEntity): return None @property - def native_unit_of_measurement(self): + def native_unit_of_measurement(self) -> str | None: """Return the unit of measurement of this entity, if any.""" try: tag = self._port.tag diff --git a/homeassistant/components/mfi/switch.py b/homeassistant/components/mfi/switch.py index 2a05018f301..1fbf7f8cb82 100644 --- a/homeassistant/components/mfi/switch.py +++ b/homeassistant/components/mfi/switch.py @@ -5,7 +5,7 @@ from __future__ import annotations import logging from typing import Any -from mficlient.client import FailedToLogin, MFiClient +from mficlient.client import FailedToLogin, MFiClient, Port as MFiPort import requests import voluptuous as vol @@ -51,18 +51,23 @@ def setup_platform( add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: - """Set up mFi sensors.""" - host = config.get(CONF_HOST) - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - use_tls = config[CONF_SSL] - verify_tls = config.get(CONF_VERIFY_SSL) + """Set up mFi switches.""" + host: str = config[CONF_HOST] + username: str = config[CONF_USERNAME] + password: str = config[CONF_PASSWORD] + use_tls: bool = config[CONF_SSL] + verify_tls: bool = config[CONF_VERIFY_SSL] default_port = 6443 if use_tls else 6080 - port = int(config.get(CONF_PORT, default_port)) + network_port: int = config.get(CONF_PORT, default_port) try: client = MFiClient( - host, username, password, port=port, use_tls=use_tls, verify=verify_tls + host, + username, + password, + port=network_port, + use_tls=use_tls, + verify=verify_tls, ) except (FailedToLogin, requests.exceptions.ConnectionError) as ex: _LOGGER.error("Unable to connect to mFi: %s", str(ex)) @@ -79,23 +84,23 @@ def setup_platform( class MfiSwitch(SwitchEntity): """Representation of an mFi switch-able device.""" - def __init__(self, port): + def __init__(self, port: MFiPort) -> None: """Initialize the mFi device.""" self._port = port - self._target_state = None + self._target_state: bool | None = None @property - def unique_id(self): + def unique_id(self) -> str: """Return the unique ID of the device.""" return self._port.ident @property - def name(self): + def name(self) -> str: """Return the name of the device.""" return self._port.label @property - def is_on(self): + def is_on(self) -> bool | None: """Return true if the device is on.""" return self._port.output diff --git a/homeassistant/components/mill/climate.py b/homeassistant/components/mill/climate.py index a9a920e3f52..3a8535b811b 100644 --- a/homeassistant/components/mill/climate.py +++ b/homeassistant/components/mill/climate.py @@ -7,6 +7,7 @@ from mill_local import OperationMode import voluptuous as vol from homeassistant.components.climate import ( + ATTR_HVAC_MODE, ClimateEntity, ClimateEntityFeature, HVACAction, @@ -111,13 +112,16 @@ class MillHeater(MillBaseEntity, ClimateEntity): super().__init__(coordinator, device) async def async_set_temperature(self, **kwargs: Any) -> None: - """Set new target temperature.""" + """Set new target temperature and optionally HVAC mode.""" if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None: return await self.coordinator.mill_data_connection.set_heater_temp( self._id, float(temperature) ) - await self.coordinator.async_request_refresh() + if (hvac_mode := kwargs.get(ATTR_HVAC_MODE)) is not None: + await self.async_handle_set_hvac_mode_service(hvac_mode) + else: + await self.coordinator.async_request_refresh() async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set new target hvac mode.""" @@ -125,12 +129,11 @@ class MillHeater(MillBaseEntity, ClimateEntity): await self.coordinator.mill_data_connection.heater_control( self._id, power_status=True ) - await self.coordinator.async_request_refresh() elif hvac_mode == HVACMode.OFF: await self.coordinator.mill_data_connection.heater_control( self._id, power_status=False ) - await self.coordinator.async_request_refresh() + await self.coordinator.async_request_refresh() @callback def _update_attr(self, device: mill.Heater) -> None: @@ -189,25 +192,26 @@ class LocalMillHeater(CoordinatorEntity[MillDataUpdateCoordinator], ClimateEntit self._update_attr() async def async_set_temperature(self, **kwargs: Any) -> None: - """Set new target temperature.""" + """Set new target temperature and optionally HVAC mode.""" if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None: return await self.coordinator.mill_data_connection.set_target_temperature( float(temperature) ) - await self.coordinator.async_request_refresh() + if (hvac_mode := kwargs.get(ATTR_HVAC_MODE)) is not None: + await self.async_handle_set_hvac_mode_service(hvac_mode) + else: + await self.coordinator.async_request_refresh() async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set new target hvac mode.""" if hvac_mode == HVACMode.HEAT: await self.coordinator.mill_data_connection.set_operation_mode_control_individually() - await self.coordinator.async_request_refresh() elif hvac_mode == HVACMode.OFF: await self.coordinator.mill_data_connection.set_operation_mode_off() - await self.coordinator.async_request_refresh() elif hvac_mode == HVACMode.AUTO: await self.coordinator.mill_data_connection.set_operation_mode_weekly_program() - await self.coordinator.async_request_refresh() + await self.coordinator.async_request_refresh() @callback def _handle_coordinator_update(self) -> None: diff --git a/homeassistant/components/minecraft_server/api.py b/homeassistant/components/minecraft_server/api.py index 8eb556319f9..cc35f0ff72b 100644 --- a/homeassistant/components/minecraft_server/api.py +++ b/homeassistant/components/minecraft_server/api.py @@ -5,8 +5,12 @@ from enum import StrEnum import logging from dns.resolver import LifetimeTimeout -from mcstatus import BedrockServer, JavaServer -from mcstatus.responses import BedrockStatusResponse, JavaStatusResponse +from mcstatus import BedrockServer, JavaServer, LegacyServer +from mcstatus.responses import ( + BedrockStatusResponse, + JavaStatusResponse, + LegacyStatusResponse, +) from homeassistant.core import HomeAssistant @@ -43,6 +47,7 @@ class MinecraftServerType(StrEnum): BEDROCK_EDITION = "Bedrock Edition" JAVA_EDITION = "Java Edition" + LEGACY_JAVA_EDITION = "Legacy Java Edition" class MinecraftServerAddressError(Exception): @@ -60,7 +65,7 @@ class MinecraftServerNotInitializedError(Exception): class MinecraftServer: """Minecraft Server wrapper class for 3rd party library mcstatus.""" - _server: BedrockServer | JavaServer | None + _server: BedrockServer | JavaServer | LegacyServer | None def __init__( self, hass: HomeAssistant, server_type: MinecraftServerType, address: str @@ -76,10 +81,12 @@ class MinecraftServer: try: if self._server_type == MinecraftServerType.JAVA_EDITION: self._server = await JavaServer.async_lookup(self._address) - else: + elif self._server_type == MinecraftServerType.BEDROCK_EDITION: self._server = await self._hass.async_add_executor_job( BedrockServer.lookup, self._address ) + else: + self._server = await LegacyServer.async_lookup(self._address) except (ValueError, LifetimeTimeout) as error: raise MinecraftServerAddressError( f"Lookup of '{self._address}' failed: {self._get_error_message(error)}" @@ -112,7 +119,9 @@ class MinecraftServer: async def async_get_data(self) -> MinecraftServerData: """Get updated data from the server, supporting both Java and Bedrock Edition servers.""" - status_response: BedrockStatusResponse | JavaStatusResponse + status_response: ( + BedrockStatusResponse | JavaStatusResponse | LegacyStatusResponse + ) if self._server is None: raise MinecraftServerNotInitializedError( @@ -128,8 +137,10 @@ class MinecraftServer: if isinstance(status_response, JavaStatusResponse): data = self._extract_java_data(status_response) - else: + elif isinstance(status_response, BedrockStatusResponse): data = self._extract_bedrock_data(status_response) + else: + data = self._extract_legacy_data(status_response) return data @@ -169,6 +180,19 @@ class MinecraftServer: map_name=status_response.map_name, ) + def _extract_legacy_data( + self, status_response: LegacyStatusResponse + ) -> MinecraftServerData: + """Extract legacy Java Edition server data out of status response.""" + return MinecraftServerData( + latency=status_response.latency, + motd=status_response.motd.to_plain(), + players_max=status_response.players.max, + players_online=status_response.players.online, + protocol_version=status_response.version.protocol, + version=status_response.version.name, + ) + def _get_error_message(self, error: BaseException) -> str: """Get error message of an exception.""" if not str(error): diff --git a/homeassistant/components/minecraft_server/config_flow.py b/homeassistant/components/minecraft_server/config_flow.py index d0f7cf5a8fb..4bcb5f6cb88 100644 --- a/homeassistant/components/minecraft_server/config_flow.py +++ b/homeassistant/components/minecraft_server/config_flow.py @@ -84,4 +84,5 @@ class MinecraftServerConfigFlow(ConfigFlow, domain=DOMAIN): } ), errors=errors, + description_placeholders={"minimum_minecraft_version": "1.4"}, ) diff --git a/homeassistant/components/minecraft_server/manifest.json b/homeassistant/components/minecraft_server/manifest.json index 1d1c02cae81..f421be8cc83 100644 --- a/homeassistant/components/minecraft_server/manifest.json +++ b/homeassistant/components/minecraft_server/manifest.json @@ -1,12 +1,12 @@ { "domain": "minecraft_server", "name": "Minecraft Server", - "codeowners": ["@elmurato"], + "codeowners": ["@elmurato", "@zachdeibert"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/minecraft_server", "integration_type": "service", "iot_class": "local_polling", "loggers": ["dnspython", "mcstatus"], "quality_scale": "silver", - "requirements": ["mcstatus==12.0.6"] + "requirements": ["mcstatus==12.1.0"] } diff --git a/homeassistant/components/minecraft_server/sensor.py b/homeassistant/components/minecraft_server/sensor.py index cfc16c7724d..c7eecec3f0d 100644 --- a/homeassistant/components/minecraft_server/sensor.py +++ b/homeassistant/components/minecraft_server/sensor.py @@ -65,6 +65,7 @@ SENSOR_DESCRIPTIONS = [ supported_server_types={ MinecraftServerType.JAVA_EDITION, MinecraftServerType.BEDROCK_EDITION, + MinecraftServerType.LEGACY_JAVA_EDITION, }, entity_category=EntityCategory.DIAGNOSTIC, ), @@ -76,6 +77,7 @@ SENSOR_DESCRIPTIONS = [ supported_server_types={ MinecraftServerType.JAVA_EDITION, MinecraftServerType.BEDROCK_EDITION, + MinecraftServerType.LEGACY_JAVA_EDITION, }, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, @@ -89,6 +91,7 @@ SENSOR_DESCRIPTIONS = [ supported_server_types={ MinecraftServerType.JAVA_EDITION, MinecraftServerType.BEDROCK_EDITION, + MinecraftServerType.LEGACY_JAVA_EDITION, }, entity_registry_enabled_default=False, ), @@ -102,6 +105,7 @@ SENSOR_DESCRIPTIONS = [ supported_server_types={ MinecraftServerType.JAVA_EDITION, MinecraftServerType.BEDROCK_EDITION, + MinecraftServerType.LEGACY_JAVA_EDITION, }, entity_category=EntityCategory.DIAGNOSTIC, ), @@ -113,6 +117,7 @@ SENSOR_DESCRIPTIONS = [ supported_server_types={ MinecraftServerType.JAVA_EDITION, MinecraftServerType.BEDROCK_EDITION, + MinecraftServerType.LEGACY_JAVA_EDITION, }, ), MinecraftServerSensorEntityDescription( @@ -124,6 +129,7 @@ SENSOR_DESCRIPTIONS = [ supported_server_types={ MinecraftServerType.JAVA_EDITION, MinecraftServerType.BEDROCK_EDITION, + MinecraftServerType.LEGACY_JAVA_EDITION, }, ), MinecraftServerSensorEntityDescription( diff --git a/homeassistant/components/minecraft_server/strings.json b/homeassistant/components/minecraft_server/strings.json index 0867db90bd8..8dfc11845b4 100644 --- a/homeassistant/components/minecraft_server/strings.json +++ b/homeassistant/components/minecraft_server/strings.json @@ -4,7 +4,7 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" }, "error": { - "cannot_connect": "Failed to connect to server. Please check the address and try again. If a port was provided, it must be within a valid range. If you are running a Minecraft Java Edition server, ensure that it is at least version 1.7." + "cannot_connect": "Failed to connect to server. Please check the address and try again. If a port was provided, it must be within a valid range. If you are running a Minecraft Java Edition server, ensure that it is at least version {minimum_minecraft_version}." }, "step": { "user": { diff --git a/homeassistant/components/mobile_app/config_flow.py b/homeassistant/components/mobile_app/config_flow.py index 33c0442b529..cd08ac5cb93 100644 --- a/homeassistant/components/mobile_app/config_flow.py +++ b/homeassistant/components/mobile_app/config_flow.py @@ -46,7 +46,7 @@ class MobileAppFlowHandler(ConfigFlow, domain=DOMAIN): "device_tracker", DOMAIN, user_input[ATTR_DEVICE_ID], - suggested_object_id=user_input[ATTR_DEVICE_NAME], + object_id_base=user_input[ATTR_DEVICE_NAME], ) await person.async_add_user_device_tracker( self.hass, user_input[CONF_USER_ID], devt_entry.entity_id diff --git a/homeassistant/components/mobile_app/manifest.json b/homeassistant/components/mobile_app/manifest.json index 6e4651ab0db..e1e394be363 100644 --- a/homeassistant/components/mobile_app/manifest.json +++ b/homeassistant/components/mobile_app/manifest.json @@ -16,5 +16,5 @@ "iot_class": "local_push", "loggers": ["nacl"], "quality_scale": "internal", - "requirements": ["PyNaCl==1.6.0"] + "requirements": ["PyNaCl==1.6.2"] } diff --git a/homeassistant/components/mobile_app/notify.py b/homeassistant/components/mobile_app/notify.py index 1980c80ce69..a7d15e32853 100644 --- a/homeassistant/components/mobile_app/notify.py +++ b/homeassistant/components/mobile_app/notify.py @@ -6,6 +6,7 @@ import asyncio from functools import partial from http import HTTPStatus import logging +from typing import Any import aiohttp @@ -47,7 +48,7 @@ from .util import supports_push _LOGGER = logging.getLogger(__name__) -def push_registrations(hass): +def push_registrations(hass: HomeAssistant) -> dict[str, str]: """Return a dictionary of push enabled registrations.""" targets = {} @@ -90,38 +91,32 @@ async def async_get_service( discovery_info: DiscoveryInfoType | None = None, ) -> MobileAppNotificationService: """Get the mobile_app notification service.""" - service = hass.data[DOMAIN][DATA_NOTIFY] = MobileAppNotificationService(hass) + service = hass.data[DOMAIN][DATA_NOTIFY] = MobileAppNotificationService() return service class MobileAppNotificationService(BaseNotificationService): """Implement the notification service for mobile_app.""" - def __init__(self, hass): - """Initialize the service.""" - self._hass = hass - @property - def targets(self): + def targets(self) -> dict[str, str]: """Return a dictionary of registered targets.""" return push_registrations(self.hass) - async def async_send_message(self, message="", **kwargs): + async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to the Lambda APNS gateway.""" data = {ATTR_MESSAGE: message} # Remove default title from notifications. if ( - kwargs.get(ATTR_TITLE) is not None - and kwargs.get(ATTR_TITLE) != ATTR_TITLE_DEFAULT - ): - data[ATTR_TITLE] = kwargs.get(ATTR_TITLE) - + title_arg := kwargs.get(ATTR_TITLE) + ) is not None and title_arg != ATTR_TITLE_DEFAULT: + data[ATTR_TITLE] = title_arg if not (targets := kwargs.get(ATTR_TARGET)): targets = push_registrations(self.hass).values() - if kwargs.get(ATTR_DATA) is not None: - data[ATTR_DATA] = kwargs.get(ATTR_DATA) + if (data_arg := kwargs.get(ATTR_DATA)) is not None: + data[ATTR_DATA] = data_arg local_push_channels = self.hass.data[DOMAIN][DATA_PUSH_CHANNEL] @@ -166,7 +161,7 @@ class MobileAppNotificationService(BaseNotificationService): try: async with asyncio.timeout(10): - response = await async_get_clientsession(self._hass).post( + response = await async_get_clientsession(self.hass).post( push_url, json=target_data ) result = await response.json() diff --git a/homeassistant/components/mqtt/schemas.py b/homeassistant/components/mqtt/schemas.py index 0a9609dfc6d..0d577a76d80 100644 --- a/homeassistant/components/mqtt/schemas.py +++ b/homeassistant/components/mqtt/schemas.py @@ -73,15 +73,6 @@ SHARED_OPTIONS = [ CONF_STATE_TOPIC, ] -MQTT_ORIGIN_INFO_SCHEMA = vol.All( - vol.Schema( - { - vol.Required(CONF_NAME): cv.string, - vol.Optional(CONF_SW_VERSION): cv.string, - vol.Optional(CONF_SUPPORT_URL): cv.configuration_url, - } - ), -) _MQTT_AVAILABILITY_SINGLE_SCHEMA = vol.Schema( { diff --git a/homeassistant/components/msteams/notify.py b/homeassistant/components/msteams/notify.py index 06f9bc42e91..47ec9f04637 100644 --- a/homeassistant/components/msteams/notify.py +++ b/homeassistant/components/msteams/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import pymsteams import voluptuous as vol @@ -49,7 +50,7 @@ class MSTeamsNotificationService(BaseNotificationService): """Initialize the service.""" self._webhook_url = webhook_url - def send_message(self, message=None, **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to the webhook.""" teams_message = pymsteams.connectorcard(self._webhook_url) diff --git a/homeassistant/components/mycroft/notify.py b/homeassistant/components/mycroft/notify.py index 67203ae0564..19e29004be8 100644 --- a/homeassistant/components/mycroft/notify.py +++ b/homeassistant/components/mycroft/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any from mycroftapi import MycroftAPI @@ -10,6 +11,8 @@ from homeassistant.components.notify import BaseNotificationService from homeassistant.core import HomeAssistant from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from . import DOMAIN + _LOGGER = logging.getLogger(__name__) @@ -19,17 +22,17 @@ def get_service( discovery_info: DiscoveryInfoType | None = None, ) -> MycroftNotificationService: """Get the Mycroft notification service.""" - return MycroftNotificationService(hass.data["mycroft"]) + return MycroftNotificationService(hass.data[DOMAIN]) class MycroftNotificationService(BaseNotificationService): """The Mycroft Notification Service.""" - def __init__(self, mycroft_ip): + def __init__(self, mycroft_ip: str) -> None: """Initialize the service.""" self.mycroft_ip = mycroft_ip - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message mycroft to speak on instance.""" text = message @@ -37,4 +40,4 @@ class MycroftNotificationService(BaseNotificationService): if mycroft is not None: mycroft.speak_text(text) else: - _LOGGER.log("Could not reach this instance of mycroft") + _LOGGER.warning("Could not reach this instance of mycroft") diff --git a/homeassistant/components/namecheapdns/__init__.py b/homeassistant/components/namecheapdns/__init__.py index 7fbd49d979b..f72441f6e58 100644 --- a/homeassistant/components/namecheapdns/__init__.py +++ b/homeassistant/components/namecheapdns/__init__.py @@ -1,25 +1,20 @@ """Support for namecheap DNS services.""" -from datetime import timedelta import logging -import defusedxml.ElementTree as ET import voluptuous as vol +from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import CONF_DOMAIN, CONF_HOST, CONF_PASSWORD from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.typing import ConfigType +from .const import DOMAIN +from .coordinator import NamecheapConfigEntry, NamecheapDnsUpdateCoordinator + _LOGGER = logging.getLogger(__name__) -DOMAIN = "namecheapdns" - -INTERVAL = timedelta(minutes=5) - -UPDATE_URL = "https://dynamicdns.park-your-domain.com/update" CONFIG_SCHEMA = vol.Schema( { @@ -37,37 +32,30 @@ CONFIG_SCHEMA = vol.Schema( async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Initialize the namecheap DNS component.""" - host = config[DOMAIN][CONF_HOST] - domain = config[DOMAIN][CONF_DOMAIN] - password = config[DOMAIN][CONF_PASSWORD] - session = async_get_clientsession(hass) - - result = await _update_namecheapdns(session, host, domain, password) - - if not result: - return False - - async def update_domain_interval(now): - """Update the namecheap DNS entry.""" - await _update_namecheapdns(session, host, domain, password) - - async_track_time_interval(hass, update_domain_interval, INTERVAL) - - return result - - -async def _update_namecheapdns(session, host, domain, password): - """Update namecheap DNS entry.""" - params = {"host": host, "domain": domain, "password": password} - - resp = await session.get(UPDATE_URL, params=params) - xml_string = await resp.text() - root = ET.fromstring(xml_string) - err_count = root.find("ErrCount").text - - if int(err_count) != 0: - _LOGGER.warning("Updating namecheap domain failed: %s", domain) - return False + if DOMAIN in config: + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=config[DOMAIN] + ) + ) return True + + +async def async_setup_entry(hass: HomeAssistant, entry: NamecheapConfigEntry) -> bool: + """Set up Namecheap DynamicDNS from a config entry.""" + + coordinator = NamecheapDnsUpdateCoordinator(hass, entry) + await coordinator.async_config_entry_first_refresh() + entry.runtime_data = coordinator + + # Add a dummy listener as we do not have regular entities + entry.async_on_unload(coordinator.async_add_listener(lambda: None)) + + return True + + +async def async_unload_entry(hass: HomeAssistant, entry: NamecheapConfigEntry) -> bool: + """Unload a config entry.""" + return True diff --git a/homeassistant/components/namecheapdns/config_flow.py b/homeassistant/components/namecheapdns/config_flow.py new file mode 100644 index 00000000000..484bbe30269 --- /dev/null +++ b/homeassistant/components/namecheapdns/config_flow.py @@ -0,0 +1,139 @@ +"""Config flow for the Namecheap DynamicDNS integration.""" + +from __future__ import annotations + +import logging +from typing import Any + +from aiohttp import ClientError +import voluptuous as vol + +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult +from homeassistant.const import CONF_DOMAIN, CONF_HOST, CONF_NAME, CONF_PASSWORD +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.selector import ( + TextSelector, + TextSelectorConfig, + TextSelectorType, +) + +from .const import DOMAIN +from .helpers import update_namecheapdns +from .issue import deprecate_yaml_issue + +_LOGGER = logging.getLogger(__name__) + + +STEP_USER_DATA_SCHEMA = vol.Schema( + { + vol.Required(CONF_HOST, default="@"): cv.string, + vol.Required(CONF_DOMAIN): cv.string, + vol.Required(CONF_PASSWORD): TextSelector( + TextSelectorConfig( + type=TextSelectorType.PASSWORD, autocomplete="current-password" + ) + ), + } +) + +STEP_RECONFIGURE_DATA_SCHEMA = vol.Schema( + { + vol.Required(CONF_PASSWORD): TextSelector( + TextSelectorConfig( + type=TextSelectorType.PASSWORD, autocomplete="current-password" + ) + ), + } +) + + +class NamecheapDnsConfigFlow(ConfigFlow, domain=DOMAIN): + """Handle a config flow for Namecheap DynamicDNS.""" + + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle the initial step.""" + errors: dict[str, str] = {} + if user_input is not None: + self._async_abort_entries_match( + {CONF_HOST: user_input[CONF_HOST], CONF_DOMAIN: user_input[CONF_DOMAIN]} + ) + session = async_get_clientsession(self.hass) + try: + if not await update_namecheapdns(session, **user_input): + errors["base"] = "update_failed" + except ClientError: + _LOGGER.debug("Cannot connect", exc_info=True) + errors["base"] = "cannot_connect" + except Exception: + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + + if not errors: + return self.async_create_entry( + title=f"{user_input[CONF_HOST]}.{user_input[CONF_DOMAIN]}", + data=user_input, + ) + + return self.async_show_form( + step_id="user", + data_schema=self.add_suggested_values_to_schema( + data_schema=STEP_USER_DATA_SCHEMA, suggested_values=user_input + ), + errors=errors, + description_placeholders={"account_panel": "https://ap.www.namecheap.com/"}, + ) + + async def async_step_import(self, import_info: dict[str, Any]) -> ConfigFlowResult: + """Import config from yaml.""" + + self._async_abort_entries_match( + {CONF_HOST: import_info[CONF_HOST], CONF_DOMAIN: import_info[CONF_DOMAIN]} + ) + result = await self.async_step_user(import_info) + if errors := result.get("errors"): + deprecate_yaml_issue(self.hass, import_success=False) + return self.async_abort(reason=errors["base"]) + + deprecate_yaml_issue(self.hass, import_success=True) + return result + + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle reconfigure flow.""" + errors: dict[str, str] = {} + + entry = self._get_reconfigure_entry() + + if user_input is not None: + session = async_get_clientsession(self.hass) + try: + if not await update_namecheapdns( + session, + entry.data[CONF_HOST], + entry.data[CONF_DOMAIN], + user_input[CONF_PASSWORD], + ): + errors["base"] = "update_failed" + except ClientError: + _LOGGER.debug("Cannot connect", exc_info=True) + errors["base"] = "cannot_connect" + except Exception: + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + + if not errors: + return self.async_update_reload_and_abort( + entry, + data_updates=user_input, + ) + + return self.async_show_form( + step_id="reconfigure", + data_schema=STEP_RECONFIGURE_DATA_SCHEMA, + errors=errors, + description_placeholders={CONF_NAME: entry.title}, + ) diff --git a/homeassistant/components/namecheapdns/const.py b/homeassistant/components/namecheapdns/const.py new file mode 100644 index 00000000000..84193fac90c --- /dev/null +++ b/homeassistant/components/namecheapdns/const.py @@ -0,0 +1,6 @@ +"""Constants for the Namecheap DynamicDNS integration.""" + +DOMAIN = "namecheapdns" + + +UPDATE_URL = "https://dynamicdns.park-your-domain.com/update" diff --git a/homeassistant/components/namecheapdns/coordinator.py b/homeassistant/components/namecheapdns/coordinator.py new file mode 100644 index 00000000000..f074330ad64 --- /dev/null +++ b/homeassistant/components/namecheapdns/coordinator.py @@ -0,0 +1,61 @@ +"""Coordinator for the Namecheap DynamicDNS integration.""" + +from datetime import timedelta +import logging + +from aiohttp import ClientError + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_DOMAIN, CONF_HOST, CONF_PASSWORD +from homeassistant.core import HomeAssistant +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import DOMAIN +from .helpers import update_namecheapdns + +_LOGGER = logging.getLogger(__name__) + + +type NamecheapConfigEntry = ConfigEntry[NamecheapDnsUpdateCoordinator] + + +INTERVAL = timedelta(minutes=5) + + +class NamecheapDnsUpdateCoordinator(DataUpdateCoordinator[None]): + """Namecheap DynamicDNS update coordinator.""" + + config_entry: NamecheapConfigEntry + + def __init__(self, hass: HomeAssistant, config_entry: NamecheapConfigEntry) -> None: + """Initialize the Namecheap DynamicDNS update coordinator.""" + super().__init__( + hass, + _LOGGER, + config_entry=config_entry, + name=DOMAIN, + update_interval=INTERVAL, + ) + + self.session = async_get_clientsession(hass) + + async def _async_update_data(self) -> None: + """Update Namecheap DNS.""" + host = self.config_entry.data[CONF_HOST] + domain = self.config_entry.data[CONF_DOMAIN] + password = self.config_entry.data[CONF_PASSWORD] + + try: + if not await update_namecheapdns(self.session, host, domain, password): + raise UpdateFailed( + translation_domain=DOMAIN, + translation_key="update_failed", + translation_placeholders={CONF_DOMAIN: f"{host}.{domain}"}, + ) + except ClientError as e: + raise UpdateFailed( + translation_domain=DOMAIN, + translation_key="connection_error", + translation_placeholders={CONF_DOMAIN: f"{host}.{domain}"}, + ) from e diff --git a/homeassistant/components/namecheapdns/helpers.py b/homeassistant/components/namecheapdns/helpers.py new file mode 100644 index 00000000000..90d32819a7c --- /dev/null +++ b/homeassistant/components/namecheapdns/helpers.py @@ -0,0 +1,24 @@ +"""Helpers for the Namecheap DynamicDNS integration.""" + +import logging + +from aiohttp import ClientSession + +from .const import UPDATE_URL + +_LOGGER = logging.getLogger(__name__) + + +async def update_namecheapdns( + session: ClientSession, host: str, domain: str, password: str +): + """Update namecheap DNS entry.""" + params = {"host": host, "domain": domain, "password": password} + + resp = await session.get(UPDATE_URL, params=params) + xml_string = await resp.text() + + if "0" not in xml_string: + return False + + return True diff --git a/homeassistant/components/namecheapdns/issue.py b/homeassistant/components/namecheapdns/issue.py new file mode 100644 index 00000000000..e32e0db6c81 --- /dev/null +++ b/homeassistant/components/namecheapdns/issue.py @@ -0,0 +1,40 @@ +"""Issues for Namecheap DynamicDNS integration.""" + +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant, callback +from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue + +from .const import DOMAIN + + +@callback +def deprecate_yaml_issue(hass: HomeAssistant, *, import_success: bool) -> None: + """Deprecate yaml issue.""" + if import_success: + async_create_issue( + hass, + HOMEASSISTANT_DOMAIN, + f"deprecated_yaml_{DOMAIN}", + is_fixable=False, + issue_domain=DOMAIN, + breaks_in_ha_version="2026.8.0", + severity=IssueSeverity.WARNING, + translation_key="deprecated_yaml", + translation_placeholders={ + "domain": DOMAIN, + "integration_title": "Namecheap DynamicDNS", + }, + ) + else: + async_create_issue( + hass, + DOMAIN, + "deprecated_yaml_import_issue_error", + breaks_in_ha_version="2026.8.0", + is_fixable=False, + issue_domain=DOMAIN, + severity=IssueSeverity.WARNING, + translation_key="deprecated_yaml_import_issue_error", + translation_placeholders={ + "url": f"/config/integrations/dashboard/add?domain={DOMAIN}" + }, + ) diff --git a/homeassistant/components/namecheapdns/manifest.json b/homeassistant/components/namecheapdns/manifest.json index f50d6aed63e..cb8b708a202 100644 --- a/homeassistant/components/namecheapdns/manifest.json +++ b/homeassistant/components/namecheapdns/manifest.json @@ -1,9 +1,10 @@ { "domain": "namecheapdns", "name": "Namecheap DynamicDNS", - "codeowners": [], + "codeowners": ["@tr4nt0r"], + "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/namecheapdns", + "integration_type": "service", "iot_class": "cloud_push", - "quality_scale": "legacy", - "requirements": ["defusedxml==0.7.1"] + "requirements": [] } diff --git a/homeassistant/components/namecheapdns/strings.json b/homeassistant/components/namecheapdns/strings.json new file mode 100644 index 00000000000..b419c6261b8 --- /dev/null +++ b/homeassistant/components/namecheapdns/strings.json @@ -0,0 +1,51 @@ +{ + "config": { + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_service%]", + "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]" + }, + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "unknown": "[%key:common::config_flow::error::unknown%]", + "update_failed": "Updating DNS failed" + }, + "step": { + "reconfigure": { + "data": { + "password": "[%key:component::namecheapdns::config::step::user::data::password%]" + }, + "data_description": { + "password": "[%key:component::namecheapdns::config::step::user::data_description::password%]" + }, + "title": "Re-configure {name}" + }, + "user": { + "data": { + "domain": "[%key:common::config_flow::data::username%]", + "host": "[%key:common::config_flow::data::host%]", + "password": "Dynamic DNS password" + }, + "data_description": { + "domain": "The domain to update ('example.com')", + "host": "The host to update ('home' for home.example.com). Use '@' to update the root domain", + "password": "Dynamic DNS password for the domain" + }, + "description": "Enter your Namecheap DynamicDNS domain and password below to configure dynamic DNS updates. You can find the Dynamic DNS password in your [Namecheap account]({account_panel}) under Domain List > Manage > Advanced DNS > Dynamic DNS." + } + } + }, + "exceptions": { + "connection_error": { + "message": "Updating Namecheap DynamicDNS domain {domain} failed due to a connection error" + }, + "update_failed": { + "message": "Updating Namecheap DynamicDNS domain {domain} failed" + } + }, + "issues": { + "deprecated_yaml_import_issue_error": { + "description": "Configuring Namecheap DynamicDNS using YAML is being removed but there was an error when trying to import the YAML configuration.\n\nEnsure the YAML configuration is correct and restart Home Assistant to try again or remove the Namecheap DynamicDNS YAML configuration from your `configuration.yaml` file and continue to [set up the integration]({url}) manually.", + "title": "The Namecheap DynamicDNS YAML configuration import failed" + } + } +} diff --git a/homeassistant/components/nasweb/__init__.py b/homeassistant/components/nasweb/__init__.py index 28036d73e95..a95c48f0f81 100644 --- a/homeassistant/components/nasweb/__init__.py +++ b/homeassistant/components/nasweb/__init__.py @@ -21,6 +21,7 @@ from .nasweb_data import NASwebData PLATFORMS: list[Platform] = [ Platform.ALARM_CONTROL_PANEL, + Platform.CLIMATE, Platform.SENSOR, Platform.SWITCH, ] diff --git a/homeassistant/components/nasweb/climate.py b/homeassistant/components/nasweb/climate.py new file mode 100644 index 00000000000..0b13f015b0d --- /dev/null +++ b/homeassistant/components/nasweb/climate.py @@ -0,0 +1,168 @@ +"""Platform for NASweb thermostat.""" + +from __future__ import annotations + +import time +from typing import Any + +from webio_api import Thermostat as NASwebThermostat +from webio_api.const import KEY_THERMOSTAT + +from homeassistant.components.climate import ( + ClimateEntity, + ClimateEntityFeature, + HVACAction, + HVACMode, + UnitOfTemperature, +) +from homeassistant.components.sensor import SensorDeviceClass +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.typing import DiscoveryInfoType +from homeassistant.helpers.update_coordinator import ( + BaseCoordinatorEntity, + BaseDataUpdateCoordinatorProtocol, +) + +from . import NASwebConfigEntry +from .const import DOMAIN, STATUS_UPDATE_MAX_TIME_INTERVAL + +CLIMATE_TRANSLATION_KEY = "thermostat" + + +async def async_setup_entry( + hass: HomeAssistant, + config: NASwebConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, + discovery_info: DiscoveryInfoType | None = None, +) -> None: + """Set up Climate platform.""" + coordinator = config.runtime_data + nasweb_thermostat: NASwebThermostat = coordinator.data[KEY_THERMOSTAT] + climate = Thermostat(coordinator, nasweb_thermostat) + async_add_entities([climate]) + + +class Thermostat(ClimateEntity, BaseCoordinatorEntity): + """Entity representing NASweb thermostat.""" + + _attr_device_class = SensorDeviceClass.TEMPERATURE + _attr_has_entity_name = True + _attr_hvac_modes = [ + HVACMode.OFF, + HVACMode.HEAT, + HVACMode.COOL, + HVACMode.HEAT_COOL, + HVACMode.FAN_ONLY, + ] + _attr_max_temp = 50 + _attr_min_temp = -50 + _attr_precision = 1.0 + _attr_should_poll = False + _attr_supported_features = ClimateEntityFeature( + ClimateEntityFeature.TARGET_TEMPERATURE_RANGE + ) + _attr_target_temperature_step = 1.0 + _attr_temperature_unit = UnitOfTemperature.CELSIUS + _attr_translation_key = CLIMATE_TRANSLATION_KEY + + def __init__( + self, + coordinator: BaseDataUpdateCoordinatorProtocol, + nasweb_thermostat: NASwebThermostat, + ) -> None: + """Initialize Thermostat.""" + super().__init__(coordinator) + self._thermostat = nasweb_thermostat + self._attr_available = False + self._attr_name = nasweb_thermostat.name + self._attr_unique_id = f"{DOMAIN}.{self._thermostat.webio_serial}.thermostat" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, self._thermostat.webio_serial)} + ) + + async def async_added_to_hass(self) -> None: + """When entity is added to hass.""" + await super().async_added_to_hass() + self._handle_coordinator_update() + + def _set_attr_available( + self, entity_last_update: float, available: bool | None + ) -> None: + if ( + self.coordinator.last_update is None + or time.time() - entity_last_update >= STATUS_UPDATE_MAX_TIME_INTERVAL + ): + self._attr_available = False + else: + self._attr_available = available if available is not None else False + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self._attr_current_temperature = self._thermostat.current_temp + self._attr_target_temperature_low = self._thermostat.temp_target_min + self._attr_target_temperature_high = self._thermostat.temp_target_max + self._attr_hvac_mode = self._get_current_hvac_mode() + self._attr_hvac_action = self._get_current_action() + self._attr_name = self._thermostat.name if self._thermostat.name else None + self._set_attr_available( + self._thermostat.last_update, self._thermostat.available + ) + self.async_write_ha_state() + + def _get_current_hvac_mode(self) -> HVACMode: + have_cooling = self._thermostat.enabled_above_output + have_heating = self._thermostat.enabled_below_output + if have_cooling and have_heating: + return HVACMode.HEAT_COOL + if have_cooling: + return HVACMode.COOL + if have_heating: + return HVACMode.HEAT + if self._thermostat.enabled_inrange_output: + return HVACMode.FAN_ONLY + return HVACMode.OFF + + def _get_current_action(self) -> HVACAction: + if self._thermostat.current_temp is None: + return HVACAction.OFF + if ( + self._thermostat.temp_target_min is not None + and self._thermostat.current_temp < self._thermostat.temp_target_min + and self._thermostat.enabled_below_output + ): + return HVACAction.HEATING + if ( + self._thermostat.temp_target_max is not None + and self._thermostat.current_temp > self._thermostat.temp_target_max + and self._thermostat.enabled_above_output + ): + return HVACAction.COOLING + if ( + self._thermostat.temp_target_min is not None + and self._thermostat.temp_target_max is not None + and self._thermostat.current_temp >= self._thermostat.temp_target_min + and self._thermostat.current_temp <= self._thermostat.temp_target_max + and self._thermostat.enabled_inrange_output + ): + return HVACAction.FAN + return HVACAction.IDLE + + async def async_update(self) -> None: + """Update the entity. + + Only used by the generic entity update service. + Scheduling updates is not necessary, the coordinator takes care of updates via push notifications. + """ + + async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: + """Set HVACMode for Thermostat.""" + await self._thermostat.set_hvac_mode(hvac_mode) + + async def async_set_temperature(self, **kwargs: Any) -> None: + """Set temperature range for Thermostat.""" + await self._thermostat.set_temperature( + kwargs["target_temp_low"], kwargs["target_temp_high"] + ) diff --git a/homeassistant/components/nasweb/coordinator.py b/homeassistant/components/nasweb/coordinator.py index 2536de1a2d8..e27b81d62a6 100644 --- a/homeassistant/components/nasweb/coordinator.py +++ b/homeassistant/components/nasweb/coordinator.py @@ -23,6 +23,7 @@ _LOGGER = logging.getLogger(__name__) KEY_INPUTS = "inputs" KEY_OUTPUTS = "outputs" +KEY_THERMOSTAT = "thermostat" KEY_ZONES = "zones" @@ -104,6 +105,7 @@ class NASwebCoordinator(BaseDataUpdateCoordinatorProtocol): KEY_OUTPUTS: self.webio_api.outputs, KEY_INPUTS: self.webio_api.inputs, KEY_TEMP_SENSOR: self.webio_api.temp_sensor, + KEY_THERMOSTAT: self.webio_api.thermostat, KEY_ZONES: self.webio_api.zones, } self.async_set_updated_data(data) @@ -199,6 +201,7 @@ class NASwebCoordinator(BaseDataUpdateCoordinatorProtocol): KEY_OUTPUTS: self.webio_api.outputs, KEY_INPUTS: self.webio_api.inputs, KEY_TEMP_SENSOR: self.webio_api.temp_sensor, + KEY_THERMOSTAT: self.webio_api.thermostat, KEY_ZONES: self.webio_api.zones, } self.async_set_updated_data(new_data) diff --git a/homeassistant/components/nasweb/strings.json b/homeassistant/components/nasweb/strings.json index 274e1a29a09..4ec206f3ae5 100644 --- a/homeassistant/components/nasweb/strings.json +++ b/homeassistant/components/nasweb/strings.json @@ -29,6 +29,11 @@ "name": "Zone {index}" } }, + "climate": { + "thermostat": { + "name": "[%key:component::climate::entity_component::_::name%]" + } + }, "sensor": { "sensor_input": { "name": "Input {index}", diff --git a/homeassistant/components/nederlandse_spoorwegen/manifest.json b/homeassistant/components/nederlandse_spoorwegen/manifest.json index cba85d0197c..81423d93cae 100644 --- a/homeassistant/components/nederlandse_spoorwegen/manifest.json +++ b/homeassistant/components/nederlandse_spoorwegen/manifest.json @@ -6,6 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/nederlandse_spoorwegen", "integration_type": "service", "iot_class": "cloud_polling", - "quality_scale": "legacy", "requirements": ["nsapi==3.1.3"] } diff --git a/homeassistant/components/ness_alarm/__init__.py b/homeassistant/components/ness_alarm/__init__.py index 730a9aff765..f9ed94a014b 100644 --- a/homeassistant/components/ness_alarm/__init__.py +++ b/homeassistant/components/ness_alarm/__init__.py @@ -1,8 +1,8 @@ """Support for Ness D8X/D16X devices.""" -from collections import namedtuple import datetime import logging +from typing import NamedTuple from nessclient import ArmingMode, ArmingState, Client import voluptuous as vol @@ -25,11 +25,12 @@ from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.start import async_at_started from homeassistant.helpers.typing import ConfigType +from homeassistant.util.hass_dict import HassKey _LOGGER = logging.getLogger(__name__) DOMAIN = "ness_alarm" -DATA_NESS = "ness_alarm" +DATA_NESS: HassKey[Client] = HassKey(DOMAIN) CONF_DEVICE_PORT = "port" CONF_INFER_ARMING_STATE = "infer_arming_state" @@ -44,7 +45,13 @@ DEFAULT_INFER_ARMING_STATE = False SIGNAL_ZONE_CHANGED = "ness_alarm.zone_changed" SIGNAL_ARMING_STATE_CHANGED = "ness_alarm.arming_state_changed" -ZoneChangedData = namedtuple("ZoneChangedData", ["zone_id", "state"]) # noqa: PYI024 + +class ZoneChangedData(NamedTuple): + """Data for a zone state change.""" + + zone_id: int + state: bool + DEFAULT_ZONE_TYPE = BinarySensorDeviceClass.MOTION ZONE_SCHEMA = vol.Schema( diff --git a/homeassistant/components/ness_alarm/binary_sensor.py b/homeassistant/components/ness_alarm/binary_sensor.py index bb0fa38ef72..8feaa6c696b 100644 --- a/homeassistant/components/ness_alarm/binary_sensor.py +++ b/homeassistant/components/ness_alarm/binary_sensor.py @@ -2,7 +2,10 @@ from __future__ import annotations -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -30,18 +33,14 @@ async def async_setup_platform( configured_zones = discovery_info[CONF_ZONES] - devices = [] - - for zone_config in configured_zones: - zone_type = zone_config[CONF_ZONE_TYPE] - zone_name = zone_config[CONF_ZONE_NAME] - zone_id = zone_config[CONF_ZONE_ID] - device = NessZoneBinarySensor( - zone_id=zone_id, name=zone_name, zone_type=zone_type + async_add_entities( + NessZoneBinarySensor( + zone_id=zone_config[CONF_ZONE_ID], + name=zone_config[CONF_ZONE_NAME], + zone_type=zone_config[CONF_ZONE_TYPE], ) - devices.append(device) - - async_add_entities(devices) + for zone_config in configured_zones + ) class NessZoneBinarySensor(BinarySensorEntity): @@ -49,12 +48,14 @@ class NessZoneBinarySensor(BinarySensorEntity): _attr_should_poll = False - def __init__(self, zone_id, name, zone_type): + def __init__( + self, zone_id: int, name: str, zone_type: BinarySensorDeviceClass + ) -> None: """Initialize the binary_sensor.""" self._zone_id = zone_id - self._name = name - self._type = zone_type - self._state = 0 + self._attr_name = name + self._attr_device_class = zone_type + self._attr_is_on = False async def async_added_to_hass(self) -> None: """Register callbacks.""" @@ -64,24 +65,9 @@ class NessZoneBinarySensor(BinarySensorEntity): ) ) - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def is_on(self): - """Return true if sensor is on.""" - return self._state == 1 - - @property - def device_class(self): - """Return the class of this sensor, from DEVICE_CLASSES.""" - return self._type - @callback - def _handle_zone_change(self, data: ZoneChangedData): + def _handle_zone_change(self, data: ZoneChangedData) -> None: """Handle zone state update.""" if self._zone_id == data.zone_id: - self._state = data.state + self._attr_is_on = data.state self.async_write_ha_state() diff --git a/homeassistant/components/netgear_lte/notify.py b/homeassistant/components/netgear_lte/notify.py index 5b10398e055..8788c00ac75 100644 --- a/homeassistant/components/netgear_lte/notify.py +++ b/homeassistant/components/netgear_lte/notify.py @@ -40,7 +40,7 @@ class NetgearNotifyService(BaseNotificationService): self.modem: Modem = discovery_info["modem"] discovery_info["entry"].async_on_unload(self.async_unregister_services) - async def async_send_message(self, message="", **kwargs): + async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" if not self.modem.token: diff --git a/homeassistant/components/nexia/climate.py b/homeassistant/components/nexia/climate.py index 52ff87e11c7..1e698713935 100644 --- a/homeassistant/components/nexia/climate.py +++ b/homeassistant/components/nexia/climate.py @@ -225,7 +225,7 @@ class NexiaZone(NexiaThermostatZoneEntity, ClimateEntity): self._signal_thermostat_update() @property - def preset_mode(self): + def preset_mode(self) -> str | None: """Preset that is active.""" return self._zone.get_preset() diff --git a/homeassistant/components/nina/config_flow.py b/homeassistant/components/nina/config_flow.py index 42b68a4c76a..2eeec4de19d 100644 --- a/homeassistant/components/nina/config_flow.py +++ b/homeassistant/components/nina/config_flow.py @@ -141,7 +141,7 @@ class NinaConfigFlow(ConfigFlow, domain=DOMAIN): try: self._all_region_codes_sorted = swap_key_value( - await nina.getAllRegionalCodes() + await nina.get_all_regional_codes() ) except ApiError: return self.async_abort(reason="no_fetch") @@ -221,7 +221,7 @@ class OptionsFlowHandler(OptionsFlowWithReload): try: self._all_region_codes_sorted = swap_key_value( - await nina.getAllRegionalCodes() + await nina.get_all_regional_codes() ) except ApiError: return self.async_abort(reason="no_fetch") diff --git a/homeassistant/components/nina/coordinator.py b/homeassistant/components/nina/coordinator.py index 7097b24e41f..175b128fdba 100644 --- a/homeassistant/components/nina/coordinator.py +++ b/homeassistant/components/nina/coordinator.py @@ -66,7 +66,7 @@ class NINADataUpdateCoordinator( regions: dict[str, str] = config_entry.data[CONF_REGIONS] for region in regions: - self._nina.addRegion(region) + self._nina.add_region(region) super().__init__( hass, @@ -151,7 +151,7 @@ class NINADataUpdateCoordinator( raw_warn.sent or "", raw_warn.start or "", raw_warn.expires or "", - raw_warn.isValid(), + raw_warn.is_valid, ) warnings_for_regions.append(warning_data) diff --git a/homeassistant/components/nina/manifest.json b/homeassistant/components/nina/manifest.json index 85ac355c08d..80bcb4d24b1 100644 --- a/homeassistant/components/nina/manifest.json +++ b/homeassistant/components/nina/manifest.json @@ -8,6 +8,6 @@ "iot_class": "cloud_polling", "loggers": ["pynina"], "quality_scale": "bronze", - "requirements": ["pynina==0.3.6"], + "requirements": ["pynina==1.0.2"], "single_config_entry": true } diff --git a/homeassistant/components/nina/quality_scale.yaml b/homeassistant/components/nina/quality_scale.yaml index 8baa258e1d1..b4d8e14db85 100644 --- a/homeassistant/components/nina/quality_scale.yaml +++ b/homeassistant/components/nina/quality_scale.yaml @@ -47,12 +47,8 @@ rules: test-coverage: status: todo comment: | - Use load_json_object_fixture in tests - Patch the library instead of the HTTP requests Create a shared fixture for the mock config entry - Use snapshots for binary sensor tests Use init_integration in tests - Evaluate the need of test_config_entry_not_ready # Gold devices: done diff --git a/homeassistant/components/nmbs/manifest.json b/homeassistant/components/nmbs/manifest.json index dfeec3e3c9b..3b5831474ee 100644 --- a/homeassistant/components/nmbs/manifest.json +++ b/homeassistant/components/nmbs/manifest.json @@ -7,6 +7,5 @@ "integration_type": "service", "iot_class": "cloud_polling", "loggers": ["pyrail"], - "quality_scale": "legacy", "requirements": ["pyrail==0.4.1"] } diff --git a/homeassistant/components/notify_events/notify.py b/homeassistant/components/notify_events/notify.py index bfe0e4a2a57..92628059d68 100644 --- a/homeassistant/components/notify_events/notify.py +++ b/homeassistant/components/notify_events/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations import logging import os.path +from typing import Any from notify_events import Message @@ -123,7 +124,7 @@ class NotifyEventsNotificationService(BaseNotificationService): return msg - def send_message(self, message, **kwargs): + def send_message(self, message: str, **kwargs: Any) -> None: """Send a message.""" data = kwargs.get(ATTR_DATA) or {} token = data.get(ATTR_TOKEN, self.token) diff --git a/homeassistant/components/ntfy/manifest.json b/homeassistant/components/ntfy/manifest.json index 9d0960dfbf6..1be3c30ba49 100644 --- a/homeassistant/components/ntfy/manifest.json +++ b/homeassistant/components/ntfy/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_push", "loggers": ["aionfty"], "quality_scale": "platinum", - "requirements": ["aiontfy==0.6.1"] + "requirements": ["aiontfy==0.7.0"] } diff --git a/homeassistant/components/nuheat/climate.py b/homeassistant/components/nuheat/climate.py index 85e24c116f9..6a38bb160be 100644 --- a/homeassistant/components/nuheat/climate.py +++ b/homeassistant/components/nuheat/climate.py @@ -154,7 +154,7 @@ class NuHeatThermostat(CoordinatorEntity, ClimateEntity): return nuheat_to_fahrenheit(self._target_temperature) @property - def preset_mode(self): + def preset_mode(self) -> str: """Return current preset mode.""" return SCHEDULE_MODE_TO_PRESET_MODE_MAP.get(self._schedule_mode, PRESET_RUN) diff --git a/homeassistant/components/number/const.py b/homeassistant/components/number/const.py index d63f2ff1657..4400e76191b 100644 --- a/homeassistant/components/number/const.py +++ b/homeassistant/components/number/const.py @@ -125,7 +125,7 @@ class NumberDeviceClass(StrEnum): CO = "carbon_monoxide" """Carbon Monoxide gas concentration. - Unit of measurement: `ppm` (parts per million), `mg/m³`, `μg/m³` + Unit of measurement: `ppb` (parts per billion), `ppm` (parts per million), `mg/m³`, `μg/m³` """ CO2 = "carbon_dioxide" @@ -247,7 +247,7 @@ class NumberDeviceClass(StrEnum): NITROGEN_DIOXIDE = "nitrogen_dioxide" """Amount of NO2. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion), `μg/m³` """ NITROGEN_MONOXIDE = "nitrogen_monoxide" @@ -265,7 +265,7 @@ class NumberDeviceClass(StrEnum): OZONE = "ozone" """Amount of O3. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion), `μg/m³` """ PH = "ph" @@ -373,7 +373,7 @@ class NumberDeviceClass(StrEnum): SULPHUR_DIOXIDE = "sulphur_dioxide" """Amount of SO2. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion), `μg/m³` """ TEMPERATURE = "temperature" @@ -483,6 +483,7 @@ DEVICE_CLASS_UNITS: dict[NumberDeviceClass, set[type[StrEnum] | str | None]] = { NumberDeviceClass.BATTERY: {PERCENTAGE}, NumberDeviceClass.BLOOD_GLUCOSE_CONCENTRATION: set(UnitOfBloodGlucoseConcentration), NumberDeviceClass.CO: { + CONCENTRATION_PARTS_PER_BILLION, CONCENTRATION_PARTS_PER_MILLION, CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, @@ -516,10 +517,16 @@ DEVICE_CLASS_UNITS: dict[NumberDeviceClass, set[type[StrEnum] | str | None]] = { NumberDeviceClass.ILLUMINANCE: {LIGHT_LUX}, NumberDeviceClass.IRRADIANCE: set(UnitOfIrradiance), NumberDeviceClass.MOISTURE: {PERCENTAGE}, - NumberDeviceClass.NITROGEN_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.NITROGEN_DIOXIDE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, NumberDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - NumberDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.OZONE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, NumberDeviceClass.PH: {None}, NumberDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, NumberDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, @@ -545,7 +552,10 @@ DEVICE_CLASS_UNITS: dict[NumberDeviceClass, set[type[StrEnum] | str | None]] = { }, NumberDeviceClass.SOUND_PRESSURE: set(UnitOfSoundPressure), NumberDeviceClass.SPEED: {*UnitOfSpeed, *UnitOfVolumetricFlux}, - NumberDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + NumberDeviceClass.SULPHUR_DIOXIDE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, NumberDeviceClass.TEMPERATURE: set(UnitOfTemperature), NumberDeviceClass.TEMPERATURE_DELTA: set(UnitOfTemperature), NumberDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: { diff --git a/homeassistant/components/nx584/binary_sensor.py b/homeassistant/components/nx584/binary_sensor.py index 69e2f626049..91d50591dfb 100644 --- a/homeassistant/components/nx584/binary_sensor.py +++ b/homeassistant/components/nx584/binary_sensor.py @@ -5,6 +5,7 @@ from __future__ import annotations import logging import threading import time +from typing import Any from nx584 import client as nx584_client import requests @@ -28,8 +29,7 @@ CONF_EXCLUDE_ZONES = "exclude_zones" CONF_ZONE_TYPES = "zone_types" DEFAULT_HOST = "localhost" -DEFAULT_PORT = "5007" -DEFAULT_SSL = False +DEFAULT_PORT = 5007 ZONE_TYPES_SCHEMA = vol.Schema({cv.positive_int: BINARY_SENSOR_DEVICE_CLASSES_SCHEMA}) @@ -53,10 +53,10 @@ def setup_platform( ) -> None: """Set up the NX584 binary sensor platform.""" - host = config[CONF_HOST] - port = config[CONF_PORT] - exclude = config[CONF_EXCLUDE_ZONES] - zone_types = config[CONF_ZONE_TYPES] + host: str = config[CONF_HOST] + port: int = config[CONF_PORT] + exclude: list[int] = config[CONF_EXCLUDE_ZONES] + zone_types: dict[int, BinarySensorDeviceClass] = config[CONF_ZONE_TYPES] try: client = nx584_client.Client(f"http://{host}:{port}") @@ -90,15 +90,12 @@ class NX584ZoneSensor(BinarySensorEntity): _attr_should_poll = False - def __init__(self, zone, zone_type): + def __init__( + self, zone: dict[str, Any], zone_type: BinarySensorDeviceClass + ) -> None: """Initialize the nx594 binary sensor.""" self._zone = zone - self._zone_type = zone_type - - @property - def device_class(self): - """Return the class of this sensor, from DEVICE_CLASSES.""" - return self._zone_type + self._attr_device_class = zone_type @property def name(self): @@ -112,7 +109,7 @@ class NX584ZoneSensor(BinarySensorEntity): return self._zone["state"] @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" return { "zone_number": self._zone["number"], diff --git a/homeassistant/components/nyt_games/strings.json b/homeassistant/components/nyt_games/strings.json index 008e3c4612d..4ba1a5f8bec 100644 --- a/homeassistant/components/nyt_games/strings.json +++ b/homeassistant/components/nyt_games/strings.json @@ -8,6 +8,9 @@ "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", "unknown": "[%key:common::config_flow::error::unknown%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/oasa_telematics/sensor.py b/homeassistant/components/oasa_telematics/sensor.py index ddf4942ef25..920af78b4ee 100644 --- a/homeassistant/components/oasa_telematics/sensor.py +++ b/homeassistant/components/oasa_telematics/sensor.py @@ -2,9 +2,10 @@ from __future__ import annotations -from datetime import timedelta +from datetime import datetime, timedelta import logging from operator import itemgetter +from typing import Any import oasatelematics import voluptuous as vol @@ -55,9 +56,9 @@ def setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the OASA Telematics sensor.""" - name = config[CONF_NAME] - stop_id = config[CONF_STOP_ID] - route_id = config.get(CONF_ROUTE_ID) + name: str = config[CONF_NAME] + stop_id: str = config[CONF_STOP_ID] + route_id: str = config[CONF_ROUTE_ID] data = OASATelematicsData(stop_id, route_id) @@ -68,42 +69,31 @@ class OASATelematicsSensor(SensorEntity): """Implementation of the OASA Telematics sensor.""" _attr_attribution = "Data retrieved from telematics.oasa.gr" + _attr_device_class = SensorDeviceClass.TIMESTAMP _attr_icon = "mdi:bus" - def __init__(self, data, stop_id, route_id, name): + def __init__( + self, data: OASATelematicsData, stop_id: str, route_id: str, name: str + ) -> None: """Initialize the sensor.""" self.data = data - self._name = name + self._attr_name = name self._stop_id = stop_id self._route_id = route_id - self._name_data = self._times = self._state = None + self._name_data: dict[str, Any] | None = None + self._times: list[dict[str, Any]] | None = None @property - def name(self): - """Return the name of the sensor.""" - return self._name - - @property - def device_class(self): - """Return the class of this sensor.""" - return SensorDeviceClass.TIMESTAMP - - @property - def native_value(self): - """Return the state of the sensor.""" - return self._state - - @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" params = {} if self._times is not None: next_arrival_data = self._times[0] if ATTR_NEXT_ARRIVAL in next_arrival_data: - next_arrival = next_arrival_data[ATTR_NEXT_ARRIVAL] + next_arrival: datetime = next_arrival_data[ATTR_NEXT_ARRIVAL] params.update({ATTR_NEXT_ARRIVAL: next_arrival.isoformat()}) if len(self._times) > 1: - second_next_arrival_time = self._times[1][ATTR_NEXT_ARRIVAL] + second_next_arrival_time: datetime = self._times[1][ATTR_NEXT_ARRIVAL] if second_next_arrival_time is not None: second_arrival = second_next_arrival_time params.update( @@ -115,12 +105,13 @@ class OASATelematicsSensor(SensorEntity): ATTR_STOP_ID: self._stop_id, } ) - params.update( - { - ATTR_ROUTE_NAME: self._name_data[ATTR_ROUTE_NAME], - ATTR_STOP_NAME: self._name_data[ATTR_STOP_NAME], - } - ) + if self._name_data is not None: + params.update( + { + ATTR_ROUTE_NAME: self._name_data[ATTR_ROUTE_NAME], + ATTR_STOP_NAME: self._name_data[ATTR_STOP_NAME], + } + ) return {k: v for k, v in params.items() if v} def update(self) -> None: @@ -130,7 +121,7 @@ class OASATelematicsSensor(SensorEntity): self._name_data = self.data.name_data next_arrival_data = self._times[0] if ATTR_NEXT_ARRIVAL in next_arrival_data: - self._state = next_arrival_data[ATTR_NEXT_ARRIVAL] + self._attr_native_value = next_arrival_data[ATTR_NEXT_ARRIVAL] class OASATelematicsData: diff --git a/homeassistant/components/ollama/const.py b/homeassistant/components/ollama/const.py index 093e20f5140..6fcc5a959df 100644 --- a/homeassistant/components/ollama/const.py +++ b/homeassistant/components/ollama/const.py @@ -158,7 +158,7 @@ MODEL_NAMES = [ # https://ollama.com/library "yi", "zephyr", ] -DEFAULT_MODEL = "qwen3:4b" +DEFAULT_MODEL = "qwen3:4b-instruct" DEFAULT_CONVERSATION_NAME = "Ollama Conversation" DEFAULT_AI_TASK_NAME = "Ollama AI Task" diff --git a/homeassistant/components/onedrive/backup.py b/homeassistant/components/onedrive/backup.py index c02fbdfa01d..a851871dbbd 100644 --- a/homeassistant/components/onedrive/backup.py +++ b/homeassistant/components/onedrive/backup.py @@ -178,6 +178,7 @@ class OneDriveBackupAgent(BackupAgent): file, upload_chunk_size=upload_chunk_size, session=async_get_clientsession(self._hass), + smart_chunk_size=True, ) except HashMismatchError as err: raise BackupAgentError( diff --git a/homeassistant/components/onedrive/manifest.json b/homeassistant/components/onedrive/manifest.json index df861f99751..79be8d85b55 100644 --- a/homeassistant/components/onedrive/manifest.json +++ b/homeassistant/components/onedrive/manifest.json @@ -10,5 +10,5 @@ "iot_class": "cloud_polling", "loggers": ["onedrive_personal_sdk"], "quality_scale": "platinum", - "requirements": ["onedrive-personal-sdk==0.0.17"] + "requirements": ["onedrive-personal-sdk==0.1.1"] } diff --git a/homeassistant/components/onedrive/strings.json b/homeassistant/components/onedrive/strings.json index 2c4db4b2fd1..25955296cc2 100644 --- a/homeassistant/components/onedrive/strings.json +++ b/homeassistant/components/onedrive/strings.json @@ -25,6 +25,9 @@ "folder_creation_error": "Failed to create folder", "folder_rename_error": "Failed to rename folder" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "folder_name": { "data": { diff --git a/homeassistant/components/onewire/const.py b/homeassistant/components/onewire/const.py index 6a60e98eb87..dabe2f560f4 100644 --- a/homeassistant/components/onewire/const.py +++ b/homeassistant/components/onewire/const.py @@ -28,7 +28,7 @@ DEVICE_SUPPORT = { "3A": (), "3B": (), "42": (), - "7E": ("EDS0066", "EDS0068"), + "7E": ("EDS0065", "EDS0066", "EDS0068"), "A6": (), "EF": ("HB_HUB", "HB_MOISTURE_METER", "HobbyBoards_EF"), } diff --git a/homeassistant/components/onewire/sensor.py b/homeassistant/components/onewire/sensor.py index f54b66b059d..b627a1d5a4d 100644 --- a/homeassistant/components/onewire/sensor.py +++ b/homeassistant/components/onewire/sensor.py @@ -297,6 +297,20 @@ HOBBYBOARD_EF: dict[str, tuple[OneWireSensorEntityDescription, ...]] = { # 7E sensors are special sensors by Embedded Data Systems EDS_SENSORS: dict[str, tuple[OneWireSensorEntityDescription, ...]] = { + "EDS0065": ( + OneWireSensorEntityDescription( + key="EDS0065/temperature", + device_class=SensorDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + state_class=SensorStateClass.MEASUREMENT, + ), + OneWireSensorEntityDescription( + key="EDS0065/humidity", + device_class=SensorDeviceClass.HUMIDITY, + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + ), "EDS0066": ( OneWireSensorEntityDescription( key="EDS0066/temperature", diff --git a/homeassistant/components/openai_conversation/__init__.py b/homeassistant/components/openai_conversation/__init__.py index b4c9a16693a..f8e4b09f3ce 100644 --- a/homeassistant/components/openai_conversation/__init__.py +++ b/homeassistant/components/openai_conversation/__init__.py @@ -25,6 +25,7 @@ from homeassistant.core import ( SupportsResponse, ) from homeassistant.exceptions import ( + ConfigEntryAuthFailed, ConfigEntryNotReady, HomeAssistantError, ServiceValidationError, @@ -96,6 +97,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: response_format="url", n=1, ) + except openai.AuthenticationError as err: + entry.async_start_reauth(hass) + raise HomeAssistantError("Authentication error") from err except openai.OpenAIError as err: raise HomeAssistantError(f"Error generating image: {err}") from err @@ -179,7 +183,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: try: response: Response = await client.responses.create(**model_args) - + except openai.AuthenticationError as err: + entry.async_start_reauth(hass) + raise HomeAssistantError("Authentication error") from err except openai.OpenAIError as err: raise HomeAssistantError(f"Error generating content: {err}") from err except FileNotFoundError as err: @@ -245,8 +251,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: OpenAIConfigEntry) -> bo try: await hass.async_add_executor_job(client.with_options(timeout=10.0).models.list) except openai.AuthenticationError as err: - LOGGER.error("Invalid API key: %s", err) - return False + raise ConfigEntryAuthFailed(err) from err except openai.OpenAIError as err: raise ConfigEntryNotReady(err) from err @@ -259,7 +264,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: OpenAIConfigEntry) -> bo return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: OpenAIConfigEntry) -> bool: """Unload OpenAI.""" return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) @@ -280,7 +285,7 @@ async def async_migrate_integration(hass: HomeAssistant) -> None: if not any(entry.version == 1 for entry in entries): return - api_keys_entries: dict[str, tuple[ConfigEntry, bool]] = {} + api_keys_entries: dict[str, tuple[OpenAIConfigEntry, bool]] = {} entity_registry = er.async_get(hass) device_registry = dr.async_get(hass) diff --git a/homeassistant/components/openai_conversation/ai_task.py b/homeassistant/components/openai_conversation/ai_task.py index 91933a36bb9..29badc0bc82 100644 --- a/homeassistant/components/openai_conversation/ai_task.py +++ b/homeassistant/components/openai_conversation/ai_task.py @@ -10,7 +10,6 @@ from typing import TYPE_CHECKING from openai.types.responses.response_output_item import ImageGenerationCall from homeassistant.components import ai_task, conversation -from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback @@ -35,7 +34,7 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + config_entry: OpenAIConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up AI Task entities.""" diff --git a/homeassistant/components/openai_conversation/config_flow.py b/homeassistant/components/openai_conversation/config_flow.py index cdfd3b72cfc..5cc604ca16b 100644 --- a/homeassistant/components/openai_conversation/config_flow.py +++ b/homeassistant/components/openai_conversation/config_flow.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import Mapping import json import logging from typing import Any @@ -12,6 +13,7 @@ from voluptuous_openapi import convert from homeassistant.components.zone import ENTITY_ID_HOME from homeassistant.config_entries import ( + SOURCE_REAUTH, ConfigEntry, ConfigEntryState, ConfigFlow, @@ -112,47 +114,72 @@ class OpenAIConfigFlow(ConfigFlow, domain=DOMAIN): self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Handle the initial step.""" - if user_input is None: - return self.async_show_form( - step_id="user", data_schema=STEP_USER_DATA_SCHEMA - ) errors: dict[str, str] = {} - self._async_abort_entries_match(user_input) - try: - await validate_input(self.hass, user_input) - except openai.APIConnectionError: - errors["base"] = "cannot_connect" - except openai.AuthenticationError: - errors["base"] = "invalid_auth" - except Exception: - _LOGGER.exception("Unexpected exception") - errors["base"] = "unknown" - else: - return self.async_create_entry( - title="ChatGPT", - data=user_input, - subentries=[ - { - "subentry_type": "conversation", - "data": RECOMMENDED_CONVERSATION_OPTIONS, - "title": DEFAULT_CONVERSATION_NAME, - "unique_id": None, - }, - { - "subentry_type": "ai_task_data", - "data": RECOMMENDED_AI_TASK_OPTIONS, - "title": DEFAULT_AI_TASK_NAME, - "unique_id": None, - }, - ], - ) + if user_input is not None: + self._async_abort_entries_match(user_input) + try: + await validate_input(self.hass, user_input) + except openai.APIConnectionError: + errors["base"] = "cannot_connect" + except openai.AuthenticationError: + errors["base"] = "invalid_auth" + except Exception: + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + else: + if self.source == SOURCE_REAUTH: + return self.async_update_reload_and_abort( + self._get_reauth_entry(), data_updates=user_input + ) + return self.async_create_entry( + title="ChatGPT", + data=user_input, + subentries=[ + { + "subentry_type": "conversation", + "data": RECOMMENDED_CONVERSATION_OPTIONS, + "title": DEFAULT_CONVERSATION_NAME, + "unique_id": None, + }, + { + "subentry_type": "ai_task_data", + "data": RECOMMENDED_AI_TASK_OPTIONS, + "title": DEFAULT_AI_TASK_NAME, + "unique_id": None, + }, + ], + ) return self.async_show_form( - step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors + step_id="user", + data_schema=self.add_suggested_values_to_schema( + STEP_USER_DATA_SCHEMA, user_input + ), + errors=errors, + description_placeholders={ + "instructions_url": "https://www.home-assistant.io/integrations/openai_conversation/#generate-an-api-key", + }, ) + async def async_step_reauth( + self, entry_data: Mapping[str, Any] + ) -> ConfigFlowResult: + """Perform reauth upon an API authentication error.""" + return await self.async_step_reauth_confirm() + + async def async_step_reauth_confirm( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Dialog that informs the user that reauth is required.""" + if not user_input: + return self.async_show_form( + step_id="reauth_confirm", data_schema=STEP_USER_DATA_SCHEMA + ) + + return await self.async_step_user(user_input) + @classmethod @callback def async_get_supported_subentry_types( diff --git a/homeassistant/components/openai_conversation/const.py b/homeassistant/components/openai_conversation/const.py index 3ba488d87db..70352952023 100644 --- a/homeassistant/components/openai_conversation/const.py +++ b/homeassistant/components/openai_conversation/const.py @@ -89,6 +89,8 @@ UNSUPPORTED_EXTENDED_CACHE_RETENTION_MODELS: list[str] = [ "gpt-3.5", "gpt-4-turbo", "gpt-4o", + "gpt-4.1-mini", + "gpt-4.1-nano", "gpt-5-mini", "gpt-5-nano", ] diff --git a/homeassistant/components/openai_conversation/strings.json b/homeassistant/components/openai_conversation/strings.json index 4b870d23c30..c8e6f333e8e 100644 --- a/homeassistant/components/openai_conversation/strings.json +++ b/homeassistant/components/openai_conversation/strings.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" + "already_configured": "[%key:common::config_flow::abort::already_configured_service%]", + "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" }, "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", @@ -9,10 +10,23 @@ "unknown": "[%key:common::config_flow::error::unknown%]" }, "step": { + "reauth_confirm": { + "data": { + "api_key": "[%key:common::config_flow::data::api_key%]" + }, + "data_description": { + "api_key": "[%key:component::openai_conversation::config::step::user::data_description::api_key%]" + }, + "description": "Reauthentication required. Please enter your updated API key." + }, "user": { "data": { "api_key": "[%key:common::config_flow::data::api_key%]" - } + }, + "data_description": { + "api_key": "Your OpenAI API key." + }, + "description": "Set up OpenAI Conversation integration by providing your OpenAI API key. Instructions to obtain an API key can be found [here]({instructions_url})." } } }, diff --git a/homeassistant/components/openevse/__init__.py b/homeassistant/components/openevse/__init__.py index b5043844524..b2847d8f785 100644 --- a/homeassistant/components/openevse/__init__.py +++ b/homeassistant/components/openevse/__init__.py @@ -4,27 +4,35 @@ from __future__ import annotations from openevsehttp.__main__ import OpenEVSE -from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, Platform +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryError +from homeassistant.exceptions import ConfigEntryNotReady -type OpenEVSEConfigEntry = ConfigEntry[OpenEVSE] +from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator async def async_setup_entry(hass: HomeAssistant, entry: OpenEVSEConfigEntry) -> bool: - """Set up openevse from a config entry.""" + """Set up OpenEVSE from a config entry.""" + charger = OpenEVSE( + entry.data[CONF_HOST], + entry.data.get(CONF_USERNAME), + entry.data.get(CONF_PASSWORD), + ) - entry.runtime_data = OpenEVSE(entry.data[CONF_HOST]) try: - await entry.runtime_data.test_and_get() + await charger.test_and_get() except TimeoutError as ex: - raise ConfigEntryError("Unable to connect to charger") from ex + raise ConfigEntryNotReady("Unable to connect to charger") from ex + + coordinator = OpenEVSEDataUpdateCoordinator(hass, entry, charger) + await coordinator.async_config_entry_first_refresh() + + entry.runtime_data = coordinator await hass.config_entries.async_forward_entry_setups(entry, [Platform.SENSOR]) return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, entry: OpenEVSEConfigEntry) -> bool: """Unload a config entry.""" return await hass.config_entries.async_unload_platforms(entry, [Platform.SENSOR]) diff --git a/homeassistant/components/openevse/config_flow.py b/homeassistant/components/openevse/config_flow.py index 5eb2b775aff..129de7635fc 100644 --- a/homeassistant/components/openevse/config_flow.py +++ b/homeassistant/components/openevse/config_flow.py @@ -3,14 +3,22 @@ from typing import Any from openevsehttp.__main__ import OpenEVSE +from openevsehttp.exceptions import AuthenticationError, MissingSerial import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult -from homeassistant.const import CONF_HOST, CONF_NAME +from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME +from homeassistant.helpers import config_validation as cv from homeassistant.helpers.service_info import zeroconf from .const import CONF_ID, CONF_SERIAL, DOMAIN +USER_SCHEMA = vol.Schema({vol.Required(CONF_HOST): cv.string}) + +AUTH_SCHEMA = vol.Schema( + {vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string} +) + class OpenEVSEConfigFlow(ConfigFlow, domain=DOMAIN): """OpenEVSE config flow.""" @@ -21,39 +29,49 @@ class OpenEVSEConfigFlow(ConfigFlow, domain=DOMAIN): def __init__(self) -> None: """Set up the instance.""" self.discovery_info: dict[str, Any] = {} + self._host: str | None = None - async def check_status(self, host: str) -> tuple[bool, str | None]: + async def check_status( + self, host: str, user: str | None = None, password: str | None = None + ) -> tuple[dict[str, str], str | None]: """Check if we can connect to the OpenEVSE charger.""" - charger = OpenEVSE(host) + charger = OpenEVSE(host, user, password) try: result = await charger.test_and_get() except TimeoutError: - return False, None - return True, result.get(CONF_SERIAL) + return {"base": "cannot_connect"}, None + except AuthenticationError: + return {"base": "invalid_auth"}, None + except MissingSerial: + return {}, None + return {}, result.get(CONF_SERIAL) async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Handle the initial step.""" - errors = {} + errors: dict[str, str] = {} if user_input is not None: self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]}) + errors, serial = await self.check_status(user_input[CONF_HOST]) - if (result := await self.check_status(user_input[CONF_HOST]))[0]: - if (serial := result[1]) is not None: + if not errors: + if serial is not None: await self.async_set_unique_id(serial, raise_on_progress=False) self._abort_if_unique_id_configured() return self.async_create_entry( title=f"OpenEVSE {user_input[CONF_HOST]}", data=user_input, ) - errors = {CONF_HOST: "cannot_connect"} + if errors["base"] == "invalid_auth": + self._host = user_input[CONF_HOST] + return await self.async_step_auth() return self.async_show_form( step_id="user", - data_schema=vol.Schema({vol.Required(CONF_HOST): str}), + data_schema=self.add_suggested_values_to_schema(USER_SCHEMA, user_input), errors=errors, ) @@ -61,9 +79,10 @@ class OpenEVSEConfigFlow(ConfigFlow, domain=DOMAIN): """Handle the initial step.""" self._async_abort_entries_match({CONF_HOST: data[CONF_HOST]}) + errors, serial = await self.check_status(data[CONF_HOST]) - if (result := await self.check_status(data[CONF_HOST]))[0]: - if (serial := result[1]) is not None: + if not errors: + if serial is not None: await self.async_set_unique_id(serial) self._abort_if_unique_id_configured() else: @@ -92,17 +111,20 @@ class OpenEVSEConfigFlow(ConfigFlow, domain=DOMAIN): } ) self.context.update({"title_placeholders": {"name": name}}) - - if not (await self.check_status(host))[0]: - return self.async_abort(reason="cannot_connect") - return await self.async_step_discovery_confirm() async def async_step_discovery_confirm( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Confirm discovery.""" + errors, _ = await self.check_status(self.discovery_info[CONF_HOST]) + if errors: + if errors["base"] == "invalid_auth": + return await self.async_step_auth() + return self.async_abort(reason="unavailable_host") + if user_input is None: + self._set_confirm_only() return self.async_show_form( step_id="discovery_confirm", description_placeholders={"name": self.discovery_info[CONF_NAME]}, @@ -112,3 +134,36 @@ class OpenEVSEConfigFlow(ConfigFlow, domain=DOMAIN): title=self.discovery_info[CONF_NAME], data={CONF_HOST: self.discovery_info[CONF_HOST]}, ) + + async def async_step_auth( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle the authentication step.""" + + errors: dict[str, str] = {} + if user_input is not None: + host = self._host or self.discovery_info[CONF_HOST] + errors, serial = await self.check_status( + host, + user_input[CONF_USERNAME], + user_input[CONF_PASSWORD], + ) + + if not errors: + if self.unique_id is None and serial is not None: + await self.async_set_unique_id(serial) + self._abort_if_unique_id_configured() + return self.async_create_entry( + title=f"OpenEVSE {host}", + data={ + CONF_HOST: host, + CONF_USERNAME: user_input[CONF_USERNAME], + CONF_PASSWORD: user_input[CONF_PASSWORD], + }, + ) + + return self.async_show_form( + step_id="auth", + data_schema=self.add_suggested_values_to_schema(AUTH_SCHEMA, user_input), + errors=errors, + ) diff --git a/homeassistant/components/openevse/coordinator.py b/homeassistant/components/openevse/coordinator.py new file mode 100644 index 00000000000..84bed399a65 --- /dev/null +++ b/homeassistant/components/openevse/coordinator.py @@ -0,0 +1,51 @@ +"""Data update coordinator for OpenEVSE.""" + +from __future__ import annotations + +from datetime import timedelta +import logging + +from openevsehttp.__main__ import OpenEVSE + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +SCAN_INTERVAL = timedelta(seconds=30) + +type OpenEVSEConfigEntry = ConfigEntry[OpenEVSEDataUpdateCoordinator] + + +class OpenEVSEDataUpdateCoordinator(DataUpdateCoordinator[None]): + """Class to manage fetching OpenEVSE data.""" + + config_entry: OpenEVSEConfigEntry + + def __init__( + self, + hass: HomeAssistant, + config_entry: OpenEVSEConfigEntry, + charger: OpenEVSE, + ) -> None: + """Initialize coordinator.""" + self.charger = charger + super().__init__( + hass, + _LOGGER, + config_entry=config_entry, + name=DOMAIN, + update_interval=SCAN_INTERVAL, + ) + + async def _async_update_data(self) -> None: + """Fetch data from OpenEVSE charger.""" + try: + await self.charger.update() + except TimeoutError as error: + raise UpdateFailed( + f"Timeout communicating with charger: {error}" + ) from error diff --git a/homeassistant/components/openevse/sensor.py b/homeassistant/components/openevse/sensor.py index 330f1eeec82..6321c70e22c 100644 --- a/homeassistant/components/openevse/sensor.py +++ b/homeassistant/components/openevse/sensor.py @@ -2,13 +2,14 @@ from __future__ import annotations +from collections.abc import Callable +from dataclasses import dataclass import logging from openevsehttp.__main__ import OpenEVSE import voluptuous as vol from homeassistant.components.sensor import ( - DOMAIN as HOMEASSISTANT_DOMAIN, PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA, SensorDeviceClass, SensorEntity, @@ -25,7 +26,7 @@ from homeassistant.const import ( UnitOfTemperature, UnitOfTime, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import config_validation as cv, issue_registry as ir from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo @@ -33,61 +34,82 @@ from homeassistant.helpers.entity_platform import ( AddConfigEntryEntitiesCallback, AddEntitiesCallback, ) -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType +from homeassistant.helpers.update_coordinator import CoordinatorEntity -from . import ConfigEntry from .const import DOMAIN, INTEGRATION_TITLE +from .coordinator import OpenEVSEConfigEntry, OpenEVSEDataUpdateCoordinator _LOGGER = logging.getLogger(__name__) -SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( - SensorEntityDescription( +PARALLEL_UPDATES = 0 + + +@dataclass(frozen=True, kw_only=True) +class OpenEVSESensorDescription(SensorEntityDescription): + """Describes an OpenEVSE sensor entity.""" + + value_fn: Callable[[OpenEVSE], str | float | None] + + +SENSOR_TYPES: tuple[OpenEVSESensorDescription, ...] = ( + OpenEVSESensorDescription( key="status", translation_key="status", + value_fn=lambda ev: ev.status, ), - SensorEntityDescription( + OpenEVSESensorDescription( key="charge_time", translation_key="charge_time", - native_unit_of_measurement=UnitOfTime.MINUTES, + native_unit_of_measurement=UnitOfTime.SECONDS, + suggested_unit_of_measurement=UnitOfTime.MINUTES, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda ev: ev.charge_time_elapsed, ), - SensorEntityDescription( + OpenEVSESensorDescription( key="ambient_temp", translation_key="ambient_temp", native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda ev: ev.ambient_temperature, ), - SensorEntityDescription( + OpenEVSESensorDescription( key="ir_temp", translation_key="ir_temp", native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda ev: ev.ir_temperature, entity_registry_enabled_default=False, ), - SensorEntityDescription( + OpenEVSESensorDescription( key="rtc_temp", translation_key="rtc_temp", native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, + value_fn=lambda ev: ev.rtc_temperature, entity_registry_enabled_default=False, ), - SensorEntityDescription( + OpenEVSESensorDescription( key="usage_session", translation_key="usage_session", - native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda ev: ev.usage_session, ), - SensorEntityDescription( + OpenEVSESensorDescription( key="usage_total", translation_key="usage_total", - native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL_INCREASING, + value_fn=lambda ev: ev.usage_total, ), ) @@ -154,41 +176,34 @@ async def async_setup_platform( async def async_setup_entry( hass: HomeAssistant, - config_entry: ConfigEntry, + entry: OpenEVSEConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: - """Add sensors for passed config_entry in HA.""" + """Set up OpenEVSE sensors based on config entry.""" + coordinator = entry.runtime_data + identifier = entry.unique_id or entry.entry_id async_add_entities( - ( - OpenEVSESensor( - config_entry.runtime_data, - description, - config_entry.entry_id, - config_entry.unique_id, - ) - for description in SENSOR_TYPES - ), - True, + OpenEVSESensor(coordinator, description, identifier, entry.unique_id) + for description in SENSOR_TYPES ) -class OpenEVSESensor(SensorEntity): +class OpenEVSESensor(CoordinatorEntity[OpenEVSEDataUpdateCoordinator], SensorEntity): """Implementation of an OpenEVSE sensor.""" _attr_has_entity_name = True + entity_description: OpenEVSESensorDescription def __init__( self, - charger: OpenEVSE, - description: SensorEntityDescription, - entry_id: str, + coordinator: OpenEVSEDataUpdateCoordinator, + description: OpenEVSESensorDescription, + identifier: str, unique_id: str | None, ) -> None: """Initialize the sensor.""" + super().__init__(coordinator) self.entity_description = description - self.charger = charger - - identifier = unique_id or entry_id self._attr_unique_id = f"{identifier}-{description.key}" self._attr_device_info = DeviceInfo( @@ -201,28 +216,7 @@ class OpenEVSESensor(SensorEntity): } self._attr_device_info[ATTR_SERIAL_NUMBER] = unique_id - async def async_update(self) -> None: - """Get the monitored data from the charger.""" - try: - await self.charger.update() - except TimeoutError: - _LOGGER.warning("Could not update status for %s", self.name) - return - - sensor_type = self.entity_description.key - if sensor_type == "status": - self._attr_native_value = self.charger.status - elif sensor_type == "charge_time": - self._attr_native_value = self.charger.charge_time_elapsed / 60 - elif sensor_type == "ambient_temp": - self._attr_native_value = self.charger.ambient_temperature - elif sensor_type == "ir_temp": - self._attr_native_value = self.charger.ir_temperature - elif sensor_type == "rtc_temp": - self._attr_native_value = self.charger.rtc_temperature - elif sensor_type == "usage_session": - self._attr_native_value = float(self.charger.usage_session) / 1000 - elif sensor_type == "usage_total": - self._attr_native_value = float(self.charger.usage_total) / 1000 - else: - self._attr_native_value = "Unknown" + @property + def native_value(self) -> StateType: + """Return the state of the sensor.""" + return self.entity_description.value_fn(self.coordinator.charger) diff --git a/homeassistant/components/openevse/strings.json b/homeassistant/components/openevse/strings.json index 593b1ff1bbc..f3f75f541d8 100644 --- a/homeassistant/components/openevse/strings.json +++ b/homeassistant/components/openevse/strings.json @@ -5,9 +5,20 @@ "unavailable_host": "Unable to connect to host" }, "error": { - "cannot_connect": "Unable to connect" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]" }, "step": { + "auth": { + "data": { + "password": "[%key:common::config_flow::data::password%]", + "username": "[%key:common::config_flow::data::username%]" + }, + "data_description": { + "password": "The password to access your OpenEVSE charger", + "username": "The username to access your OpenEVSE charger" + } + }, "user": { "data": { "host": "[%key:common::config_flow::data::host%]" @@ -44,6 +55,10 @@ } }, "issues": { + "deprecated_yaml_import_issue_unavailable_host": { + "description": "Configuring {integration_title} using YAML is being removed but there was a connection error while trying to import the YAML configuration.\n\nEnsure your OpenEVSE charger is accessible and restart Home Assistant to try again.", + "title": "The {integration_title} YAML configuration import failed" + }, "yaml_deprecated": { "description": "Configuring OpenEVSE using YAML is being removed. Your existing YAML configuration has been imported into the UI automatically. Remove the `openevse` configuration from your configuration.yaml file and restart Home Assistant to fix this issue.", "title": "OpenEVSE YAML configuration is deprecated" diff --git a/homeassistant/components/opower/manifest.json b/homeassistant/components/opower/manifest.json index 036e4c2b973..9c9b55920a7 100644 --- a/homeassistant/components/opower/manifest.json +++ b/homeassistant/components/opower/manifest.json @@ -9,5 +9,5 @@ "iot_class": "cloud_polling", "loggers": ["opower"], "quality_scale": "bronze", - "requirements": ["opower==0.16.1"] + "requirements": ["opower==0.16.4"] } diff --git a/homeassistant/components/overkiz/climate/atlantic_electrical_heater_with_adjustable_temperature_setpoint.py b/homeassistant/components/overkiz/climate/atlantic_electrical_heater_with_adjustable_temperature_setpoint.py index a24e3abd732..fb449f4bbd3 100644 --- a/homeassistant/components/overkiz/climate/atlantic_electrical_heater_with_adjustable_temperature_setpoint.py +++ b/homeassistant/components/overkiz/climate/atlantic_electrical_heater_with_adjustable_temperature_setpoint.py @@ -128,15 +128,15 @@ class AtlanticElectricalHeaterWithAdjustableTemperatureSetpoint( states = self.device.states - if ( - operating_mode := states[OverkizState.CORE_OPERATING_MODE] - ) and operating_mode.value_as_str == OverkizCommandParam.EXTERNAL: - return PRESET_EXTERNAL - if ( state := states[OverkizState.IO_TARGET_HEATING_LEVEL] ) and state.value_as_str: return OVERKIZ_TO_PRESET_MODE[state.value_as_str] + + if ( + operating_mode := states[OverkizState.CORE_OPERATING_MODE] + ) and operating_mode.value_as_str == OverkizCommandParam.EXTERNAL: + return PRESET_EXTERNAL return None async def async_set_preset_mode(self, preset_mode: str) -> None: diff --git a/homeassistant/components/owntracks/manifest.json b/homeassistant/components/owntracks/manifest.json index 81da21b2a54..ade83e87473 100644 --- a/homeassistant/components/owntracks/manifest.json +++ b/homeassistant/components/owntracks/manifest.json @@ -9,6 +9,6 @@ "integration_type": "service", "iot_class": "local_push", "loggers": ["nacl"], - "requirements": ["PyNaCl==1.6.0"], + "requirements": ["PyNaCl==1.6.2"], "single_config_entry": true } diff --git a/homeassistant/components/playstation_network/strings.json b/homeassistant/components/playstation_network/strings.json index 075e190bd71..65f448a4f39 100644 --- a/homeassistant/components/playstation_network/strings.json +++ b/homeassistant/components/playstation_network/strings.json @@ -13,6 +13,9 @@ "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", "unknown": "[%key:common::config_flow::error::unknown%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "reauth_confirm": { "data": { diff --git a/homeassistant/components/point/__init__.py b/homeassistant/components/point/__init__.py index 26176cb65a4..a670f04de40 100644 --- a/homeassistant/components/point/__init__.py +++ b/homeassistant/components/point/__init__.py @@ -7,7 +7,6 @@ from aiohttp import ClientError, ClientResponseError, web from pypoint import PointSession from homeassistant.components import webhook -from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_WEBHOOK_ID, Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady @@ -21,14 +20,12 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from . import api from .const import CONF_WEBHOOK_URL, DOMAIN, EVENT_RECEIVED, SIGNAL_WEBHOOK -from .coordinator import PointDataUpdateCoordinator +from .coordinator import PointConfigEntry, PointDataUpdateCoordinator _LOGGER = logging.getLogger(__name__) PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] -type PointConfigEntry = ConfigEntry[PointDataUpdateCoordinator] - async def async_setup_entry(hass: HomeAssistant, entry: PointConfigEntry) -> bool: """Set up Minut Point from a config entry.""" @@ -59,7 +56,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: PointConfigEntry) -> boo point_session = PointSession(auth) - coordinator = PointDataUpdateCoordinator(hass, point_session) + coordinator = PointDataUpdateCoordinator(hass, point_session, entry) await coordinator.async_config_entry_first_refresh() diff --git a/homeassistant/components/point/alarm_control_panel.py b/homeassistant/components/point/alarm_control_panel.py index 2df26283624..5902b77076d 100644 --- a/homeassistant/components/point/alarm_control_panel.py +++ b/homeassistant/components/point/alarm_control_panel.py @@ -16,8 +16,8 @@ from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from . import PointConfigEntry from .const import DOMAIN, SIGNAL_WEBHOOK +from .coordinator import PointConfigEntry _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/point/binary_sensor.py b/homeassistant/components/point/binary_sensor.py index 17fe40b9654..8113899b505 100644 --- a/homeassistant/components/point/binary_sensor.py +++ b/homeassistant/components/point/binary_sensor.py @@ -15,9 +15,8 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from . import PointConfigEntry from .const import SIGNAL_WEBHOOK -from .coordinator import PointDataUpdateCoordinator +from .coordinator import PointConfigEntry, PointDataUpdateCoordinator from .entity import MinutPointEntity _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/point/coordinator.py b/homeassistant/components/point/coordinator.py index 93bd74955ea..91e4a28c8ac 100644 --- a/homeassistant/components/point/coordinator.py +++ b/homeassistant/components/point/coordinator.py @@ -7,6 +7,7 @@ from typing import Any from pypoint import PointSession +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.util.dt import parse_datetime @@ -15,17 +16,24 @@ from .const import DOMAIN, SCAN_INTERVAL _LOGGER = logging.getLogger(__name__) +type PointConfigEntry = ConfigEntry[PointDataUpdateCoordinator] + class PointDataUpdateCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]): """Class to manage fetching Point data from the API.""" - def __init__(self, hass: HomeAssistant, point: PointSession) -> None: + config_entry: PointConfigEntry + + def __init__( + self, hass: HomeAssistant, point: PointSession, config_entry: PointConfigEntry + ) -> None: """Initialize.""" super().__init__( hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL, + config_entry=config_entry, ) self.point = point self.device_updates: dict[str, datetime] = {} diff --git a/homeassistant/components/point/sensor.py b/homeassistant/components/point/sensor.py index 246536d86ab..40b59b17575 100644 --- a/homeassistant/components/point/sensor.py +++ b/homeassistant/components/point/sensor.py @@ -14,8 +14,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.typing import StateType -from . import PointConfigEntry -from .coordinator import PointDataUpdateCoordinator +from .coordinator import PointConfigEntry, PointDataUpdateCoordinator from .entity import MinutPointEntity _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/pooldose/entity.py b/homeassistant/components/pooldose/entity.py index 4965700ce1b..013e28751c3 100644 --- a/homeassistant/components/pooldose/entity.py +++ b/homeassistant/components/pooldose/entity.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Literal +from collections.abc import Callable, Coroutine +from typing import Any, Literal from pooldose.type_definitions import DeviceInfoDict, ValueDict @@ -80,7 +81,10 @@ class PooldoseEntity(CoordinatorEntity[PooldoseCoordinator]): return platform_data.get(self.entity_description.key) async def _async_perform_write( - self, api_call, key: str, value: bool | str | float + self, + api_call: Callable[[str, Any], Coroutine[Any, Any, bool]], + key: str, + value: bool | str | float, ) -> None: """Perform a write call to the API with unified error handling. diff --git a/homeassistant/components/pooldose/manifest.json b/homeassistant/components/pooldose/manifest.json index 0fd48657a61..87610c605c2 100644 --- a/homeassistant/components/pooldose/manifest.json +++ b/homeassistant/components/pooldose/manifest.json @@ -11,6 +11,6 @@ "documentation": "https://www.home-assistant.io/integrations/pooldose", "integration_type": "device", "iot_class": "local_polling", - "quality_scale": "silver", - "requirements": ["python-pooldose==0.8.1"] + "quality_scale": "platinum", + "requirements": ["python-pooldose==0.8.2"] } diff --git a/homeassistant/components/pooldose/quality_scale.yaml b/homeassistant/components/pooldose/quality_scale.yaml index 6004d7fdb14..3de73acc596 100644 --- a/homeassistant/components/pooldose/quality_scale.yaml +++ b/homeassistant/components/pooldose/quality_scale.yaml @@ -45,12 +45,12 @@ rules: discovery-update-info: done discovery: done docs-data-update: done - docs-examples: todo + docs-examples: done docs-known-limitations: done docs-supported-devices: done docs-supported-functions: done docs-troubleshooting: done - docs-use-cases: todo + docs-use-cases: done dynamic-devices: status: exempt comment: This integration does not support dynamic device discovery, as each config entry represents a single PoolDose device with all available entities. @@ -71,4 +71,4 @@ rules: # Platinum async-dependency: done inject-websession: done - strict-typing: todo + strict-typing: done diff --git a/homeassistant/components/portainer/manifest.json b/homeassistant/components/portainer/manifest.json index fa15be5a5a1..0f35f2b68f8 100644 --- a/homeassistant/components/portainer/manifest.json +++ b/homeassistant/components/portainer/manifest.json @@ -7,5 +7,5 @@ "integration_type": "hub", "iot_class": "local_polling", "quality_scale": "bronze", - "requirements": ["pyportainer==1.0.22"] + "requirements": ["pyportainer==1.0.23"] } diff --git a/homeassistant/components/portainer/switch.py b/homeassistant/components/portainer/switch.py index 79202159685..273f984c35f 100644 --- a/homeassistant/components/portainer/switch.py +++ b/homeassistant/components/portainer/switch.py @@ -40,12 +40,13 @@ class PortainerSwitchEntityDescription(SwitchEntityDescription): async def perform_action( action: str, portainer: Portainer, endpoint_id: int, container_id: str ) -> None: - """Stop a container.""" + """Perform an action on a container.""" try: - if action == "start": - await portainer.start_container(endpoint_id, container_id) - elif action == "stop": - await portainer.stop_container(endpoint_id, container_id) + match action: + case "start": + await portainer.start_container(endpoint_id, container_id) + case "stop": + await portainer.stop_container(endpoint_id, container_id) except PortainerAuthenticationError as err: raise HomeAssistantError( translation_domain=DOMAIN, diff --git a/homeassistant/components/prowl/manifest.json b/homeassistant/components/prowl/manifest.json index 70cdc0844e7..deac43d1657 100644 --- a/homeassistant/components/prowl/manifest.json +++ b/homeassistant/components/prowl/manifest.json @@ -7,6 +7,5 @@ "integration_type": "service", "iot_class": "cloud_push", "loggers": ["prowl"], - "quality_scale": "legacy", "requirements": ["prowlpy==1.1.1"] } diff --git a/homeassistant/components/proxmoxve/__init__.py b/homeassistant/components/proxmoxve/__init__.py index 00b39957984..ed9652c55c6 100644 --- a/homeassistant/components/proxmoxve/__init__.py +++ b/homeassistant/components/proxmoxve/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations from datetime import timedelta +import logging from typing import Any from proxmoxer import AuthenticationError, ProxmoxAPI @@ -10,6 +11,7 @@ import requests.exceptions from requests.exceptions import ConnectTimeout, SSLError import voluptuous as vol +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, @@ -18,26 +20,29 @@ from homeassistant.const import ( CONF_VERIFY_SSL, Platform, ) -from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.discovery import async_load_platform +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant +from homeassistant.data_entry_flow import FlowResultType +from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady +from homeassistant.helpers import config_validation as cv, issue_registry as ir from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from .common import ProxmoxClient, call_api_container_vm, parse_api_container_vm +from .common import ( + ProxmoxClient, + ResourceException, + call_api_container_vm, + parse_api_container_vm, +) from .const import ( - _LOGGER, CONF_CONTAINERS, CONF_NODE, CONF_NODES, CONF_REALM, CONF_VMS, - COORDINATORS, DEFAULT_PORT, DEFAULT_REALM, DEFAULT_VERIFY_SSL, DOMAIN, - PROXMOX_CLIENTS, TYPE_CONTAINER, TYPE_VM, UPDATE_INTERVAL, @@ -45,6 +50,10 @@ from .const import ( PLATFORMS = [Platform.BINARY_SENSOR] +type ProxmoxConfigEntry = ConfigEntry[ + dict[str, dict[str, dict[int, DataUpdateCoordinator[dict[str, Any] | None]]]] +] + CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.All( @@ -84,109 +93,154 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) +LOGGER = logging.getLogger(__name__) + async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: - """Set up the platform.""" - hass.data.setdefault(DOMAIN, {}) + """Import the Proxmox configuration from YAML.""" + if DOMAIN not in config: + return True - def build_client() -> ProxmoxAPI: - """Build the Proxmox client connection.""" - hass.data[PROXMOX_CLIENTS] = {} - - for entry in config[DOMAIN]: - host = entry[CONF_HOST] - port = entry[CONF_PORT] - user = entry[CONF_USERNAME] - realm = entry[CONF_REALM] - password = entry[CONF_PASSWORD] - verify_ssl = entry[CONF_VERIFY_SSL] - - hass.data[PROXMOX_CLIENTS][host] = None - - try: - # Construct an API client with the given data for the given host - proxmox_client = ProxmoxClient( - host, port, user, realm, password, verify_ssl - ) - proxmox_client.build_client() - except AuthenticationError: - _LOGGER.warning( - "Invalid credentials for proxmox instance %s:%d", host, port - ) - continue - except SSLError: - _LOGGER.error( - ( - "Unable to verify proxmox server SSL. " - 'Try using "verify_ssl: false" for proxmox instance %s:%d' - ), - host, - port, - ) - continue - except ConnectTimeout: - _LOGGER.warning("Connection to host %s timed out during setup", host) - continue - except requests.exceptions.ConnectionError: - _LOGGER.warning("Host %s is not reachable", host) - continue - - hass.data[PROXMOX_CLIENTS][host] = proxmox_client - - await hass.async_add_executor_job(build_client) - - coordinators: dict[ - str, dict[str, dict[int, DataUpdateCoordinator[dict[str, Any] | None]]] - ] = {} - hass.data[DOMAIN][COORDINATORS] = coordinators - - # Create a coordinator for each vm/container - for host_config in config[DOMAIN]: - host_name = host_config["host"] - coordinators[host_name] = {} - - proxmox_client = hass.data[PROXMOX_CLIENTS][host_name] - - # Skip invalid hosts - if proxmox_client is None: - continue - - proxmox = proxmox_client.get_api_client() - - for node_config in host_config["nodes"]: - node_name = node_config["node"] - node_coordinators = coordinators[host_name][node_name] = {} - - for vm_id in node_config["vms"]: - coordinator = create_coordinator_container_vm( - hass, proxmox, host_name, node_name, vm_id, TYPE_VM - ) - - # Fetch initial data - await coordinator.async_refresh() - - node_coordinators[vm_id] = coordinator - - for container_id in node_config["containers"]: - coordinator = create_coordinator_container_vm( - hass, proxmox, host_name, node_name, container_id, TYPE_CONTAINER - ) - - # Fetch initial data - await coordinator.async_refresh() - - node_coordinators[container_id] = coordinator - - for component in PLATFORMS: - await hass.async_create_task( - async_load_platform(hass, component, DOMAIN, {"config": config}, config) - ) + hass.async_create_task(_async_setup(hass, config)) return True -def create_coordinator_container_vm( +async def _async_setup(hass: HomeAssistant, config: ConfigType) -> None: + for entry_config in config[DOMAIN]: + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data=entry_config, + ) + if ( + result.get("type") is FlowResultType.ABORT + and result.get("reason") != "already_configured" + ): + ir.async_create_issue( + hass, + DOMAIN, + f"deprecated_yaml_import_issue_{result.get('reason')}", + breaks_in_ha_version="2026.8.0", + is_fixable=False, + issue_domain=DOMAIN, + severity=ir.IssueSeverity.WARNING, + translation_key=f"deprecated_yaml_import_issue_{result.get('reason')}", + translation_placeholders={ + "domain": DOMAIN, + "integration_title": "Proxmox VE", + }, + ) + return + + ir.async_create_issue( + hass, + HOMEASSISTANT_DOMAIN, + "deprecated_yaml", + breaks_in_ha_version="2026.8.0", + is_fixable=False, + issue_domain=DOMAIN, + severity=ir.IssueSeverity.WARNING, + translation_key="deprecated_yaml", + translation_placeholders={ + "domain": DOMAIN, + "integration_title": "Proxmox VE", + }, + ) + + +async def async_setup_entry(hass: HomeAssistant, entry: ProxmoxConfigEntry) -> bool: + """Set up a ProxmoxVE instance from a config entry.""" + + def build_client() -> ProxmoxClient: + """Build and return the Proxmox client connection.""" + host = entry.data[CONF_HOST] + port = entry.data[CONF_PORT] + user = entry.data[CONF_USERNAME] + realm = entry.data[CONF_REALM] + password = entry.data[CONF_PASSWORD] + verify_ssl = entry.data[CONF_VERIFY_SSL] + try: + client = ProxmoxClient(host, port, user, realm, password, verify_ssl) + client.build_client() + except AuthenticationError as ex: + raise ConfigEntryAuthFailed("Invalid credentials") from ex + except SSLError as ex: + raise ConfigEntryAuthFailed( + f"Unable to verify proxmox server SSL. Try using 'verify_ssl: false' for proxmox instance {host}:{port}" + ) from ex + except ConnectTimeout as ex: + raise ConfigEntryNotReady("Connection timed out") from ex + except requests.exceptions.ConnectionError as ex: + raise ConfigEntryNotReady(f"Host {host} is not reachable: {ex}") from ex + else: + return client + + proxmox_client = await hass.async_add_executor_job(build_client) + + coordinators: dict[ + str, dict[str, dict[int, DataUpdateCoordinator[dict[str, Any] | None]]] + ] = {} + entry.runtime_data = coordinators + + host_name = entry.data[CONF_HOST] + coordinators[host_name] = {} + + proxmox: ProxmoxAPI = proxmox_client.get_api_client() + + for node_config in entry.data[CONF_NODES]: + node_name = node_config[CONF_NODE] + node_coordinators = coordinators[host_name][node_name] = {} + + try: + vms, containers = await hass.async_add_executor_job( + _get_vms_containers, proxmox, node_config + ) + except (ResourceException, requests.exceptions.ConnectionError) as err: + LOGGER.error("Unable to get vms/containers for node %s: %s", node_name, err) + continue + + for vm in vms: + coordinator = _create_coordinator_container_vm( + hass, entry, proxmox, host_name, node_name, vm["vmid"], TYPE_VM + ) + await coordinator.async_config_entry_first_refresh() + + node_coordinators[vm["vmid"]] = coordinator + + for container in containers: + coordinator = _create_coordinator_container_vm( + hass, + entry, + proxmox, + host_name, + node_name, + container["vmid"], + TYPE_CONTAINER, + ) + await coordinator.async_config_entry_first_refresh() + + node_coordinators[container["vmid"]] = coordinator + + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + + return True + + +def _get_vms_containers( + proxmox: ProxmoxAPI, + node_config: dict[str, Any], +) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: + """Get vms and containers for a node.""" + vms = proxmox.nodes(node_config[CONF_NODE]).qemu.get() + containers = proxmox.nodes(node_config[CONF_NODE]).lxc.get() + assert vms is not None and containers is not None + return vms, containers + + +def _create_coordinator_container_vm( hass: HomeAssistant, + entry: ProxmoxConfigEntry, proxmox: ProxmoxAPI, host_name: str, node_name: str, @@ -205,7 +259,7 @@ def create_coordinator_container_vm( vm_status = await hass.async_add_executor_job(poll_api) if vm_status is None: - _LOGGER.warning( + LOGGER.warning( "Vm/Container %s unable to be found in node %s", vm_id, node_name ) return None @@ -214,9 +268,14 @@ def create_coordinator_container_vm( return DataUpdateCoordinator( hass, - _LOGGER, - config_entry=None, + LOGGER, + config_entry=entry, name=f"proxmox_coordinator_{host_name}_{node_name}_{vm_id}", update_method=async_update_data, update_interval=timedelta(seconds=UPDATE_INTERVAL), ) + + +async def async_unload_entry(hass: HomeAssistant, entry: ProxmoxConfigEntry) -> bool: + """Unload a config entry.""" + return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/proxmoxve/binary_sensor.py b/homeassistant/components/proxmoxve/binary_sensor.py index 412f40af6e8..abc3ced24f0 100644 --- a/homeassistant/components/proxmoxve/binary_sensor.py +++ b/homeassistant/components/proxmoxve/binary_sensor.py @@ -2,55 +2,48 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from homeassistant.components.binary_sensor import ( BinarySensorDeviceClass, BinarySensorEntity, ) +from homeassistant.const import CONF_HOST from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from .const import COORDINATORS, DOMAIN, PROXMOX_CLIENTS +from . import ProxmoxConfigEntry +from .const import CONF_CONTAINERS, CONF_NODE, CONF_NODES, CONF_VMS from .entity import ProxmoxEntity -async def async_setup_platform( +async def async_setup_entry( hass: HomeAssistant, - config: ConfigType, - add_entities: AddEntitiesCallback, - discovery_info: DiscoveryInfoType | None = None, + entry: ProxmoxConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up binary sensors.""" - if discovery_info is None: - return - sensors = [] - for host_config in discovery_info["config"][DOMAIN]: - host_name = host_config["host"] - host_name_coordinators = hass.data[DOMAIN][COORDINATORS][host_name] + host_name = entry.data[CONF_HOST] + host_name_coordinators = entry.runtime_data[host_name] - if hass.data[PROXMOX_CLIENTS][host_name] is None: - continue + for node_config in entry.data[CONF_NODES]: + node_name = node_config[CONF_NODE] - for node_config in host_config["nodes"]: - node_name = node_config["node"] + for dev_id in node_config[CONF_VMS] + node_config[CONF_CONTAINERS]: + coordinator = host_name_coordinators[node_name][dev_id] - for dev_id in node_config["vms"] + node_config["containers"]: - coordinator = host_name_coordinators[node_name][dev_id] + if TYPE_CHECKING: + assert coordinator.data is not None + name = coordinator.data["name"] + sensor = create_binary_sensor( + coordinator, host_name, node_name, dev_id, name + ) + sensors.append(sensor) - # unfound case - if (coordinator_data := coordinator.data) is None: - continue - - name = coordinator_data["name"] - sensor = create_binary_sensor( - coordinator, host_name, node_name, dev_id, name - ) - sensors.append(sensor) - - add_entities(sensors) + async_add_entities(sensors) def create_binary_sensor( diff --git a/homeassistant/components/proxmoxve/config_flow.py b/homeassistant/components/proxmoxve/config_flow.py new file mode 100644 index 00000000000..74b6a74722a --- /dev/null +++ b/homeassistant/components/proxmoxve/config_flow.py @@ -0,0 +1,175 @@ +"""Config flow for Proxmox VE integration.""" + +from __future__ import annotations + +import logging +from typing import Any + +from proxmoxer import AuthenticationError, ProxmoxAPI +import requests +from requests.exceptions import ConnectTimeout, SSLError +import voluptuous as vol + +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PORT, + CONF_USERNAME, + CONF_VERIFY_SSL, +) +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import config_validation as cv + +from .common import ResourceException +from .const import ( + CONF_CONTAINERS, + CONF_NODE, + CONF_NODES, + CONF_REALM, + CONF_VMS, + DEFAULT_PORT, + DEFAULT_REALM, + DEFAULT_VERIFY_SSL, + DOMAIN, +) + +_LOGGER = logging.getLogger(__name__) +CONFIG_SCHEMA = vol.Schema( + { + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_REALM, default=DEFAULT_REALM): cv.string, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, + } +) + + +def _sanitize_userid(data: dict[str, Any]) -> str: + """Sanitize the user ID.""" + return ( + data[CONF_USERNAME] + if "@" in data[CONF_USERNAME] + else f"{data[CONF_USERNAME]}@{data[CONF_REALM]}" + ) + + +def _get_nodes_data(data: dict[str, Any]) -> list[dict[str, Any]]: + """Validate the user input and fetch data (sync, for executor).""" + try: + client = ProxmoxAPI( + data[CONF_HOST], + port=data[CONF_PORT], + user=_sanitize_userid(data), + password=data[CONF_PASSWORD], + verify_ssl=data.get(CONF_VERIFY_SSL, DEFAULT_VERIFY_SSL), + ) + nodes = client.nodes.get() + except AuthenticationError as err: + raise ProxmoxAuthenticationError from err + except SSLError as err: + raise ProxmoxSSLError from err + except ConnectTimeout as err: + raise ProxmoxConnectTimeout from err + except (ResourceException, requests.exceptions.ConnectionError) as err: + raise ProxmoxNoNodesFound from err + + _LOGGER.debug("Proxmox nodes: %s", nodes) + + nodes_data: list[dict[str, Any]] = [] + for node in nodes: + try: + vms = client.nodes(node["node"]).qemu.get() + containers = client.nodes(node["node"]).lxc.get() + except (ResourceException, requests.exceptions.ConnectionError) as err: + raise ProxmoxNoNodesFound from err + + nodes_data.append( + { + CONF_NODE: node["node"], + CONF_VMS: [vm["vmid"] for vm in vms], + CONF_CONTAINERS: [container["vmid"] for container in containers], + } + ) + + _LOGGER.debug("Nodes with data: %s", nodes_data) + return nodes_data + + +class ProxmoxveConfigFlow(ConfigFlow, domain=DOMAIN): + """Handle a config flow for Proxmox VE.""" + + VERSION = 1 + + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle the initial step.""" + errors: dict[str, str] = {} + proxmox_nodes: list[dict[str, Any]] = [] + if user_input is not None: + self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]}) + try: + proxmox_nodes = await self.hass.async_add_executor_job( + _get_nodes_data, user_input + ) + except ProxmoxConnectTimeout: + errors["base"] = "connect_timeout" + except ProxmoxAuthenticationError: + errors["base"] = "invalid_auth" + except ProxmoxSSLError: + errors["base"] = "ssl_error" + except ProxmoxNoNodesFound: + errors["base"] = "no_nodes_found" + + if not errors: + return self.async_create_entry( + title=user_input[CONF_HOST], + data={**user_input, CONF_NODES: proxmox_nodes}, + ) + + return self.async_show_form( + step_id="user", + data_schema=CONFIG_SCHEMA, + errors=errors, + ) + + async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: + """Handle a flow initiated by configuration file.""" + self._async_abort_entries_match({CONF_HOST: import_data[CONF_HOST]}) + + try: + proxmox_nodes = await self.hass.async_add_executor_job( + _get_nodes_data, import_data + ) + except ProxmoxConnectTimeout: + return self.async_abort(reason="connect_timeout") + except ProxmoxAuthenticationError: + return self.async_abort(reason="invalid_auth") + except ProxmoxSSLError: + return self.async_abort(reason="ssl_error") + except ProxmoxNoNodesFound: + return self.async_abort(reason="no_nodes_found") + + return self.async_create_entry( + title=import_data[CONF_HOST], + data={**import_data, CONF_NODES: proxmox_nodes}, + ) + + +class ProxmoxNoNodesFound(HomeAssistantError): + """Error to indicate no nodes found.""" + + +class ProxmoxConnectTimeout(HomeAssistantError): + """Error to indicate a connection timeout.""" + + +class ProxmoxSSLError(HomeAssistantError): + """Error to indicate an SSL error.""" + + +class ProxmoxAuthenticationError(HomeAssistantError): + """Error to indicate an authentication error.""" diff --git a/homeassistant/components/proxmoxve/const.py b/homeassistant/components/proxmoxve/const.py index 6477c081463..da62f89069a 100644 --- a/homeassistant/components/proxmoxve/const.py +++ b/homeassistant/components/proxmoxve/const.py @@ -1,16 +1,12 @@ """Constants for ProxmoxVE.""" -import logging - DOMAIN = "proxmoxve" -PROXMOX_CLIENTS = "proxmox_clients" CONF_REALM = "realm" CONF_NODE = "node" CONF_NODES = "nodes" CONF_VMS = "vms" CONF_CONTAINERS = "containers" -COORDINATORS = "coordinators" DEFAULT_PORT = 8006 DEFAULT_REALM = "pam" @@ -18,5 +14,3 @@ DEFAULT_VERIFY_SSL = True TYPE_VM = 0 TYPE_CONTAINER = 1 UPDATE_INTERVAL = 60 - -_LOGGER = logging.getLogger(__package__) diff --git a/homeassistant/components/proxmoxve/manifest.json b/homeassistant/components/proxmoxve/manifest.json index 45ead1330e2..35aad8b9b88 100644 --- a/homeassistant/components/proxmoxve/manifest.json +++ b/homeassistant/components/proxmoxve/manifest.json @@ -1,8 +1,10 @@ { "domain": "proxmoxve", "name": "Proxmox VE", - "codeowners": ["@jhollowe", "@Corbeno"], + "codeowners": ["@jhollowe", "@Corbeno", "@erwindouna"], + "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/proxmoxve", + "integration_type": "service", "iot_class": "local_polling", "loggers": ["proxmoxer"], "quality_scale": "legacy", diff --git a/homeassistant/components/proxmoxve/strings.json b/homeassistant/components/proxmoxve/strings.json new file mode 100644 index 00000000000..842784306b2 --- /dev/null +++ b/homeassistant/components/proxmoxve/strings.json @@ -0,0 +1,46 @@ +{ + "config": { + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + }, + "error": { + "cannot_connect": "Cannot connect to Proxmox VE server", + "connect_timeout": "[%key:common::config_flow::error::timeout_connect%]", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "no_nodes_found": "No active nodes found", + "ssl_error": "SSL check failed. Check the SSL settings" + }, + "step": { + "user": { + "data": { + "host": "[%key:common::config_flow::data::host%]", + "password": "[%key:common::config_flow::data::password%]", + "port": "[%key:common::config_flow::data::port%]", + "realm": "Realm", + "username": "[%key:common::config_flow::data::username%]", + "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]" + }, + "description": "Enter your Proxmox VE server details to set up the integration.", + "title": "Connect to Proxmox VE" + } + } + }, + "issues": { + "deprecated_yaml_import_issue_connect_timeout": { + "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, a connection timeout occurred. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", + "title": "The {integration_title} YAML configuration is being removed" + }, + "deprecated_yaml_import_issue_invalid_auth": { + "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, invalid authentication details were found. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", + "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" + }, + "deprecated_yaml_import_issue_no_nodes_found": { + "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, no active nodes were found on the Proxmox VE server. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", + "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" + }, + "deprecated_yaml_import_issue_ssl_error": { + "description": "Configuring {integration_title} via YAML is deprecated and will be removed in a future release. While importing your configuration, an SSL error occurred. Please correct your YAML configuration and restart Home Assistant, or remove the {domain} key from your configuration and configure the integration via the UI.", + "title": "[%key:component::proxmoxve::issues::deprecated_yaml_import_issue_connect_timeout::title%]" + } + } +} diff --git a/homeassistant/components/ps4/__init__.py b/homeassistant/components/ps4/__init__.py index 48e7bf92d0f..59d5929cb17 100644 --- a/homeassistant/components/ps4/__init__.py +++ b/homeassistant/components/ps4/__init__.py @@ -126,9 +126,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: "media_player", DOMAIN, unique_id, - suggested_object_id=new_id, config_entry=entry, device_id=e_entry.device_id, + object_id_base=new_id, ) _LOGGER.debug( "PlayStation 4 identifier for entity: %s has changed", diff --git a/homeassistant/components/pushsafer/notify.py b/homeassistant/components/pushsafer/notify.py index 4d6f7898a5a..1810bbc68aa 100644 --- a/homeassistant/components/pushsafer/notify.py +++ b/homeassistant/components/pushsafer/notify.py @@ -6,6 +6,7 @@ import base64 from http import HTTPStatus import logging import mimetypes +from typing import Any import requests from requests.auth import HTTPBasicAuth @@ -65,26 +66,23 @@ def get_service( discovery_info: DiscoveryInfoType | None = None, ) -> PushsaferNotificationService: """Get the Pushsafer.com notification service.""" - return PushsaferNotificationService( - config.get(CONF_DEVICE_KEY), hass.config.is_allowed_path - ) + return PushsaferNotificationService(config[CONF_DEVICE_KEY]) class PushsaferNotificationService(BaseNotificationService): """Implementation of the notification service for Pushsafer.com.""" - def __init__(self, private_key, is_allowed_path): + def __init__(self, private_key: str) -> None: """Initialize the service.""" self._private_key = private_key - self.is_allowed_path = is_allowed_path - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to specified target.""" - if kwargs.get(ATTR_TARGET) is None: + targets: list[str] | None + if (targets := kwargs.get(ATTR_TARGET)) is None: targets = ["a"] _LOGGER.debug("No target specified. Sending push to all") else: - targets = kwargs.get(ATTR_TARGET) _LOGGER.debug("%s target(s) specified", len(targets)) title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) @@ -170,7 +168,7 @@ class PushsaferNotificationService(BaseNotificationService): try: if local_path is not None: _LOGGER.debug("Loading image from local path") - if self.is_allowed_path(local_path): + if self.hass.config.is_allowed_path(local_path): file_mimetype = mimetypes.guess_type(local_path) _LOGGER.debug("Detected mimetype %s", file_mimetype) with open(local_path, "rb") as binary_file: diff --git a/homeassistant/components/qingping/manifest.json b/homeassistant/components/qingping/manifest.json index 454e84c1867..ba62d35dede 100644 --- a/homeassistant/components/qingping/manifest.json +++ b/homeassistant/components/qingping/manifest.json @@ -21,5 +21,5 @@ "documentation": "https://www.home-assistant.io/integrations/qingping", "integration_type": "device", "iot_class": "local_push", - "requirements": ["qingping-ble==1.0.1"] + "requirements": ["qingping-ble==1.1.0"] } diff --git a/homeassistant/components/qnap_qsw/manifest.json b/homeassistant/components/qnap_qsw/manifest.json index d5370c26fcf..d7d5c2545e2 100644 --- a/homeassistant/components/qnap_qsw/manifest.json +++ b/homeassistant/components/qnap_qsw/manifest.json @@ -9,6 +9,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/qnap_qsw", + "integration_type": "device", "iot_class": "local_polling", "loggers": ["aioqsw"], "requirements": ["aioqsw==0.4.2"] diff --git a/homeassistant/components/qwikswitch/__init__.py b/homeassistant/components/qwikswitch/__init__.py index d3cf2ff3d9b..7dedee04508 100644 --- a/homeassistant/components/qwikswitch/__init__.py +++ b/homeassistant/components/qwikswitch/__init__.py @@ -24,9 +24,9 @@ from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.typing import ConfigType -_LOGGER = logging.getLogger(__name__) +from .const import DATA_QUIKSWITCH, DOMAIN -DOMAIN = "qwikswitch" +_LOGGER = logging.getLogger(__name__) CONF_DIMMER_ADJUST = "dimmer_adjust" CONF_BUTTON_EVENTS = "button_events" @@ -96,7 +96,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: if not await qsusb.update_from_devices(): return False - hass.data[DOMAIN] = qsusb + hass.data[DATA_QUIKSWITCH] = qsusb comps: dict[Platform, list] = { Platform.SWITCH: [], @@ -168,7 +168,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: @callback def async_stop(_): """Stop the listener.""" - hass.data[DOMAIN].stop() + hass.data[DATA_QUIKSWITCH].stop() hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, async_stop) diff --git a/homeassistant/components/qwikswitch/binary_sensor.py b/homeassistant/components/qwikswitch/binary_sensor.py index bbe8d309e50..25a9917297e 100644 --- a/homeassistant/components/qwikswitch/binary_sensor.py +++ b/homeassistant/components/qwikswitch/binary_sensor.py @@ -3,15 +3,19 @@ from __future__ import annotations import logging +from typing import Any from pyqwikswitch.qwikswitch import SENSORS -from homeassistant.components.binary_sensor import BinarySensorEntity +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN +from .const import DATA_QUIKSWITCH, DOMAIN from .entity import QSEntity _LOGGER = logging.getLogger(__name__) @@ -27,7 +31,7 @@ async def async_setup_platform( if discovery_info is None: return - qsusb = hass.data[DOMAIN] + qsusb = hass.data[DATA_QUIKSWITCH] _LOGGER.debug("Setup qwikswitch.binary_sensor %s, %s", qsusb, discovery_info) devs = [QSBinarySensor(sensor) for sensor in discovery_info[DOMAIN]] add_entities(devs) @@ -36,9 +40,7 @@ async def async_setup_platform( class QSBinarySensor(QSEntity, BinarySensorEntity): """Sensor based on a Qwikswitch relay/dimmer module.""" - _val = False - - def __init__(self, sensor): + def __init__(self, sensor: dict[str, Any]) -> None: """Initialize the sensor.""" super().__init__(sensor["id"], sensor["name"]) @@ -47,7 +49,9 @@ class QSBinarySensor(QSEntity, BinarySensorEntity): self._decode, _ = SENSORS[sensor_type] self._invert = not sensor.get("invert", False) - self._class = sensor.get("class", "door") + self._attr_is_on = not self._invert + self._attr_device_class = sensor.get("class", BinarySensorDeviceClass.DOOR) + self._attr_unique_id = f"qs{self.qsid}:{self.channel}" @callback def update_packet(self, packet): @@ -62,20 +66,5 @@ class QSBinarySensor(QSEntity, BinarySensorEntity): packet, ) if val is not None: - self._val = bool(val) + self._attr_is_on = bool(val) == self._invert self.async_write_ha_state() - - @property - def is_on(self): - """Check if device is on (non-zero).""" - return self._val == self._invert - - @property - def unique_id(self): - """Return a unique identifier for this sensor.""" - return f"qs{self.qsid}:{self.channel}" - - @property - def device_class(self): - """Return the class of this sensor.""" - return self._class diff --git a/homeassistant/components/qwikswitch/const.py b/homeassistant/components/qwikswitch/const.py new file mode 100644 index 00000000000..2a5cc69af50 --- /dev/null +++ b/homeassistant/components/qwikswitch/const.py @@ -0,0 +1,13 @@ +"""Support for Qwikswitch devices.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from homeassistant.util.hass_dict import HassKey + +if TYPE_CHECKING: + from pyqwikswitch.async_ import QSUsb + +DOMAIN = "qwikswitch" +DATA_QUIKSWITCH: HassKey[QSUsb] = HassKey(DOMAIN) diff --git a/homeassistant/components/qwikswitch/entity.py b/homeassistant/components/qwikswitch/entity.py index ff7a1d2e98a..e163b4708a7 100644 --- a/homeassistant/components/qwikswitch/entity.py +++ b/homeassistant/components/qwikswitch/entity.py @@ -7,7 +7,7 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity -from . import DOMAIN +from .const import DATA_QUIKSWITCH class QSEntity(Entity): @@ -15,21 +15,12 @@ class QSEntity(Entity): _attr_should_poll = False - def __init__(self, qsid, name): + def __init__(self, qsid: str, name: str) -> None: """Initialize the QSEntity.""" - self._name = name + self._attr_name = name + self._attr_unique_id = f"qs{qsid}" self.qsid = qsid - @property - def name(self): - """Return the name of the sensor.""" - return self._name - - @property - def unique_id(self): - """Return a unique identifier for this sensor.""" - return f"qs{self.qsid}" - @callback def update_packet(self, packet): """Receive update packet from QSUSB. Match dispather_send signature.""" @@ -67,8 +58,8 @@ class QSToggleEntity(QSEntity): async def async_turn_on(self, **kwargs): """Turn the device on.""" new = kwargs.get(ATTR_BRIGHTNESS, 255) - self.hass.data[DOMAIN].devices.set_value(self.qsid, new) + self.hass.data[DATA_QUIKSWITCH].devices.set_value(self.qsid, new) async def async_turn_off(self, **_): """Turn the device off.""" - self.hass.data[DOMAIN].devices.set_value(self.qsid, 0) + self.hass.data[DATA_QUIKSWITCH].devices.set_value(self.qsid, 0) diff --git a/homeassistant/components/qwikswitch/sensor.py b/homeassistant/components/qwikswitch/sensor.py index e87fae83464..8a3a4f01032 100644 --- a/homeassistant/components/qwikswitch/sensor.py +++ b/homeassistant/components/qwikswitch/sensor.py @@ -12,7 +12,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN +from .const import DATA_QUIKSWITCH, DOMAIN from .entity import QSEntity _LOGGER = logging.getLogger(__name__) @@ -28,7 +28,7 @@ async def async_setup_platform( if discovery_info is None: return - qsusb = hass.data[DOMAIN] + qsusb = hass.data[DATA_QUIKSWITCH] _LOGGER.debug("Setup qwikswitch.sensor %s, %s", qsusb, discovery_info) devs = [QSSensor(sensor) for sensor in discovery_info[DOMAIN]] add_entities(devs) @@ -37,21 +37,24 @@ async def async_setup_platform( class QSSensor(QSEntity, SensorEntity): """Sensor based on a Qwikswitch relay/dimmer module.""" - _val: Any | None = None - - def __init__(self, sensor): + def __init__(self, sensor: dict[str, Any]) -> None: """Initialize the sensor.""" super().__init__(sensor["id"], sensor["name"]) self.channel = sensor["channel"] sensor_type = sensor["type"] - self._decode, self.unit = SENSORS[sensor_type] + self._attr_unique_id = f"qs{self.qsid}:{self.channel}" + + decode, unit = SENSORS[sensor_type] # this cannot happen because it only happens in bool and this should be redirected to binary_sensor - assert not isinstance(self.unit, type), ( + assert not isinstance(unit, type), ( f"boolean sensor id={sensor['id']} name={sensor['name']}" ) + self._decode = decode + self._attr_native_unit_of_measurement = unit + @callback def update_packet(self, packet): """Receive update packet from QSUSB.""" @@ -65,20 +68,5 @@ class QSSensor(QSEntity, SensorEntity): packet, ) if val is not None: - self._val = val + self._attr_native_value = str(val) self.async_write_ha_state() - - @property - def native_value(self): - """Return the value of the sensor.""" - return None if self._val is None else str(self._val) - - @property - def unique_id(self): - """Return a unique identifier for this sensor.""" - return f"qs{self.qsid}:{self.channel}" - - @property - def native_unit_of_measurement(self): - """Return the unit the value is expressed in.""" - return self.unit diff --git a/homeassistant/components/qwikswitch/switch.py b/homeassistant/components/qwikswitch/switch.py index 6131d9e595c..4b3cddee0d9 100644 --- a/homeassistant/components/qwikswitch/switch.py +++ b/homeassistant/components/qwikswitch/switch.py @@ -7,7 +7,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN +from .const import DATA_QUIKSWITCH, DOMAIN from .entity import QSToggleEntity @@ -21,7 +21,7 @@ async def async_setup_platform( if discovery_info is None: return - qsusb = hass.data[DOMAIN] + qsusb = hass.data[DATA_QUIKSWITCH] devs = [QSSwitch(qsid, qsusb) for qsid in discovery_info[DOMAIN]] add_entities(devs) diff --git a/homeassistant/components/rabbitair/manifest.json b/homeassistant/components/rabbitair/manifest.json index 8f4df8afb7b..f8d80dc5ffc 100644 --- a/homeassistant/components/rabbitair/manifest.json +++ b/homeassistant/components/rabbitair/manifest.json @@ -5,6 +5,7 @@ "codeowners": ["@rabbit-air"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rabbitair", + "integration_type": "device", "iot_class": "local_polling", "requirements": ["python-rabbitair==0.0.8"], "zeroconf": ["_rabbitair._udp.local."] diff --git a/homeassistant/components/radiotherm/manifest.json b/homeassistant/components/radiotherm/manifest.json index 185a034d7f2..916a2b7261e 100644 --- a/homeassistant/components/radiotherm/manifest.json +++ b/homeassistant/components/radiotherm/manifest.json @@ -13,6 +13,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/radiotherm", + "integration_type": "device", "iot_class": "local_polling", "loggers": ["radiotherm"], "requirements": ["radiotherm==2.1.0"] diff --git a/homeassistant/components/rainbird/manifest.json b/homeassistant/components/rainbird/manifest.json index 2364b7b014f..93b4f21d7cb 100644 --- a/homeassistant/components/rainbird/manifest.json +++ b/homeassistant/components/rainbird/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@konikvranik", "@allenporter"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rainbird", + "integration_type": "hub", "iot_class": "local_polling", "loggers": ["pyrainbird"], "requirements": ["pyrainbird==6.0.1"] diff --git a/homeassistant/components/rainforest_raven/manifest.json b/homeassistant/components/rainforest_raven/manifest.json index c21241f1cc9..dc22586833c 100644 --- a/homeassistant/components/rainforest_raven/manifest.json +++ b/homeassistant/components/rainforest_raven/manifest.json @@ -5,6 +5,7 @@ "config_flow": true, "dependencies": ["usb"], "documentation": "https://www.home-assistant.io/integrations/rainforest_raven", + "integration_type": "hub", "iot_class": "local_polling", "requirements": ["aioraven==0.7.1"], "usb": [ diff --git a/homeassistant/components/rapt_ble/manifest.json b/homeassistant/components/rapt_ble/manifest.json index 2684240708f..79a6269f819 100644 --- a/homeassistant/components/rapt_ble/manifest.json +++ b/homeassistant/components/rapt_ble/manifest.json @@ -15,6 +15,7 @@ "config_flow": true, "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/rapt_ble", + "integration_type": "device", "iot_class": "local_push", "requirements": ["rapt-ble==0.1.2"] } diff --git a/homeassistant/components/recorder/statistics.py b/homeassistant/components/recorder/statistics.py index 1b3841fc107..73964eb7e0e 100644 --- a/homeassistant/components/recorder/statistics.py +++ b/homeassistant/components/recorder/statistics.py @@ -59,11 +59,14 @@ from homeassistant.util.unit_conversion import ( InformationConverter, MassConverter, MassVolumeConcentrationConverter, + NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, ReactivePowerConverter, SpeedConverter, + SulphurDioxideConcentrationConverter, TemperatureConverter, TemperatureDeltaConverter, UnitlessRatioConverter, @@ -224,6 +227,9 @@ _PRIMARY_UNIT_CONVERTERS: list[type[BaseUnitConverter]] = [ _SECONDARY_UNIT_CONVERTERS: list[type[BaseUnitConverter]] = [ CarbonMonoxideConcentrationConverter, + NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, + SulphurDioxideConcentrationConverter, TemperatureDeltaConverter, ] diff --git a/homeassistant/components/recorder/websocket_api.py b/homeassistant/components/recorder/websocket_api.py index 09d820485dc..0689caaf5bc 100644 --- a/homeassistant/components/recorder/websocket_api.py +++ b/homeassistant/components/recorder/websocket_api.py @@ -33,11 +33,14 @@ from homeassistant.util.unit_conversion import ( InformationConverter, MassConverter, MassVolumeConcentrationConverter, + NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, ReactivePowerConverter, SpeedConverter, + SulphurDioxideConcentrationConverter, TemperatureConverter, TemperatureDeltaConverter, UnitlessRatioConverter, @@ -84,21 +87,28 @@ UNIT_SCHEMA = vol.Schema( vol.Optional("distance"): vol.In(DistanceConverter.VALID_UNITS), vol.Optional("duration"): vol.In(DurationConverter.VALID_UNITS), vol.Optional("electric_current"): vol.In(ElectricCurrentConverter.VALID_UNITS), - vol.Optional("voltage"): vol.In(ElectricPotentialConverter.VALID_UNITS), vol.Optional("energy"): vol.In(EnergyConverter.VALID_UNITS), vol.Optional("energy_distance"): vol.In(EnergyDistanceConverter.VALID_UNITS), vol.Optional("information"): vol.In(InformationConverter.VALID_UNITS), vol.Optional("mass"): vol.In(MassConverter.VALID_UNITS), + vol.Optional("nitrogen_dioxide"): vol.In( + NitrogenDioxideConcentrationConverter.VALID_UNITS + ), + vol.Optional("ozone"): vol.In(OzoneConcentrationConverter.VALID_UNITS), vol.Optional("power"): vol.In(PowerConverter.VALID_UNITS), vol.Optional("pressure"): vol.In(PressureConverter.VALID_UNITS), vol.Optional("reactive_energy"): vol.In(ReactiveEnergyConverter.VALID_UNITS), vol.Optional("reactive_power"): vol.In(ReactivePowerConverter.VALID_UNITS), vol.Optional("speed"): vol.In(SpeedConverter.VALID_UNITS), + vol.Optional("sulphur_dioxide"): vol.In( + SulphurDioxideConcentrationConverter.VALID_UNITS + ), vol.Optional("temperature"): vol.In(TemperatureConverter.VALID_UNITS), vol.Optional("temperature_delta"): vol.In( TemperatureDeltaConverter.VALID_UNITS ), vol.Optional("unitless"): vol.In(UnitlessRatioConverter.VALID_UNITS), + vol.Optional("voltage"): vol.In(ElectricPotentialConverter.VALID_UNITS), vol.Optional("volume"): vol.In(VolumeConverter.VALID_UNITS), vol.Optional("volume_flow_rate"): vol.In(VolumeFlowRateConverter.VALID_UNITS), } diff --git a/homeassistant/components/refoss/manifest.json b/homeassistant/components/refoss/manifest.json index 93ffe5b3f26..5227d783f1f 100644 --- a/homeassistant/components/refoss/manifest.json +++ b/homeassistant/components/refoss/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@ashionky"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/refoss", + "integration_type": "hub", "iot_class": "local_polling", "requirements": ["refoss-ha==1.2.5"], "single_config_entry": true diff --git a/homeassistant/components/rehlko/manifest.json b/homeassistant/components/rehlko/manifest.json index d73f8c42584..ab4805472ff 100644 --- a/homeassistant/components/rehlko/manifest.json +++ b/homeassistant/components/rehlko/manifest.json @@ -10,6 +10,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/rehlko", + "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["aiokem"], "quality_scale": "silver", diff --git a/homeassistant/components/renault/strings.json b/homeassistant/components/renault/strings.json index e5f9b54cd7a..1685c1b1cae 100644 --- a/homeassistant/components/renault/strings.json +++ b/homeassistant/components/renault/strings.json @@ -12,6 +12,9 @@ "invalid_credentials": "[%key:common::config_flow::error::invalid_auth%]", "unknown": "[%key:common::config_flow::error::unknown%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "kamereon": { "data": { diff --git a/homeassistant/components/renson/manifest.json b/homeassistant/components/renson/manifest.json index fcc482959f2..2c1e24244ae 100644 --- a/homeassistant/components/renson/manifest.json +++ b/homeassistant/components/renson/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@jimmyd-be"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/renson", + "integration_type": "device", "iot_class": "local_polling", "requirements": ["renson-endura-delta==1.7.2"] } diff --git a/homeassistant/components/rfxtrx/manifest.json b/homeassistant/components/rfxtrx/manifest.json index bb3701e2e31..34df4c26c18 100644 --- a/homeassistant/components/rfxtrx/manifest.json +++ b/homeassistant/components/rfxtrx/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@danielhiversen", "@elupus", "@RobBie1221"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rfxtrx", + "integration_type": "hub", "iot_class": "local_push", "loggers": ["RFXtrx"], "requirements": ["pyRFXtrx==0.31.1"] diff --git a/homeassistant/components/rituals_perfume_genie/manifest.json b/homeassistant/components/rituals_perfume_genie/manifest.json index 0acee2ae604..39d5084c1a3 100644 --- a/homeassistant/components/rituals_perfume_genie/manifest.json +++ b/homeassistant/components/rituals_perfume_genie/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@milanmeu", "@frenck", "@quebulm"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rituals_perfume_genie", + "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["pyrituals"], "requirements": ["pyrituals==0.0.7"] diff --git a/homeassistant/components/rocketchat/notify.py b/homeassistant/components/rocketchat/notify.py index 20ae0708c15..96eda4b5609 100644 --- a/homeassistant/components/rocketchat/notify.py +++ b/homeassistant/components/rocketchat/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations from http import HTTPStatus import logging +from typing import Any from rocketchat_API.APIExceptions.RocketExceptions import ( RocketAuthenticationException, @@ -69,7 +70,7 @@ class RocketChatNotificationService(BaseNotificationService): self._room = room self._server = RocketChat(username, password, server_url=url) - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to Rocket.Chat.""" data = kwargs.get(ATTR_DATA) or {} resp = self._server.chat_post_message(message, channel=self._room, **data) diff --git a/homeassistant/components/romy/manifest.json b/homeassistant/components/romy/manifest.json index efb8072ebbc..1169bee99ff 100644 --- a/homeassistant/components/romy/manifest.json +++ b/homeassistant/components/romy/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@xeniter"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/romy", + "integration_type": "device", "iot_class": "local_polling", "requirements": ["romy==0.0.10"], "zeroconf": ["_aicu-http._tcp.local."] diff --git a/homeassistant/components/roomba/manifest.json b/homeassistant/components/roomba/manifest.json index 24af14bfba3..1ded2f6a9ce 100644 --- a/homeassistant/components/roomba/manifest.json +++ b/homeassistant/components/roomba/manifest.json @@ -22,6 +22,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/roomba", + "integration_type": "device", "iot_class": "local_push", "loggers": ["paho_mqtt", "roombapy"], "requirements": ["roombapy==1.9.0"], diff --git a/homeassistant/components/roon/manifest.json b/homeassistant/components/roon/manifest.json index 0dcb5b87581..f583f89e3eb 100644 --- a/homeassistant/components/roon/manifest.json +++ b/homeassistant/components/roon/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@pavoni"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/roon", + "integration_type": "hub", "iot_class": "local_push", "loggers": ["roonapi"], "requirements": ["roonapi==0.1.6"] diff --git a/homeassistant/components/rova/manifest.json b/homeassistant/components/rova/manifest.json index b867cac8e7a..b541d60bd2d 100644 --- a/homeassistant/components/rova/manifest.json +++ b/homeassistant/components/rova/manifest.json @@ -4,6 +4,7 @@ "codeowners": [], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rova", + "integration_type": "service", "iot_class": "cloud_polling", "loggers": ["rova"], "requirements": ["rova==0.4.1"] diff --git a/homeassistant/components/russound_rio/manifest.json b/homeassistant/components/russound_rio/manifest.json index 5973d1ccea6..43683722a0c 100644 --- a/homeassistant/components/russound_rio/manifest.json +++ b/homeassistant/components/russound_rio/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@noahhusby"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/russound_rio", + "integration_type": "hub", "iot_class": "local_push", "loggers": ["aiorussound"], "quality_scale": "silver", diff --git a/homeassistant/components/ruuvi_gateway/manifest.json b/homeassistant/components/ruuvi_gateway/manifest.json index a9284893973..92fdfd823cd 100644 --- a/homeassistant/components/ruuvi_gateway/manifest.json +++ b/homeassistant/components/ruuvi_gateway/manifest.json @@ -10,6 +10,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/ruuvi_gateway", + "integration_type": "device", "iot_class": "local_polling", "requirements": ["aioruuvigateway==0.1.0"] } diff --git a/homeassistant/components/ruuvitag_ble/manifest.json b/homeassistant/components/ruuvitag_ble/manifest.json index 586e227cc78..bf70dbaa413 100644 --- a/homeassistant/components/ruuvitag_ble/manifest.json +++ b/homeassistant/components/ruuvitag_ble/manifest.json @@ -15,6 +15,7 @@ "config_flow": true, "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/ruuvitag_ble", + "integration_type": "device", "iot_class": "local_push", "requirements": ["ruuvitag-ble==0.4.0"] } diff --git a/homeassistant/components/rympro/manifest.json b/homeassistant/components/rympro/manifest.json index 51c26b312fb..a6c8705afdd 100644 --- a/homeassistant/components/rympro/manifest.json +++ b/homeassistant/components/rympro/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@OnFreund", "@elad-bar", "@maorcc"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/rympro", + "integration_type": "hub", "iot_class": "cloud_polling", "requirements": ["pyrympro==0.0.9"] } diff --git a/homeassistant/components/sabnzbd/manifest.json b/homeassistant/components/sabnzbd/manifest.json index f1b8a17134b..2b17f3484d0 100644 --- a/homeassistant/components/sabnzbd/manifest.json +++ b/homeassistant/components/sabnzbd/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@shaiu", "@jpbede"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/sabnzbd", + "integration_type": "service", "iot_class": "local_polling", "loggers": ["pysabnzbd"], "quality_scale": "bronze", diff --git a/homeassistant/components/saunum/__init__.py b/homeassistant/components/saunum/__init__.py index e9bea5f7c06..e2988b4b713 100644 --- a/homeassistant/components/saunum/__init__.py +++ b/homeassistant/components/saunum/__init__.py @@ -26,11 +26,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: LeilSaunaConfigEntry) -> """Set up Saunum Leil Sauna from a config entry.""" host = entry.data[CONF_HOST] - client = SaunumClient(host=host) - - # Test connection try: - await client.connect() + client = await SaunumClient.create(host) except SaunumConnectionError as exc: raise ConfigEntryNotReady(f"Error connecting to {host}: {exc}") from exc @@ -47,7 +44,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: LeilSaunaConfigEntry) -> async def async_unload_entry(hass: HomeAssistant, entry: LeilSaunaConfigEntry) -> bool: """Unload a config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - coordinator = entry.runtime_data - coordinator.client.close() + await entry.runtime_data.client.async_close() return unload_ok diff --git a/homeassistant/components/saunum/climate.py b/homeassistant/components/saunum/climate.py index f90703edea2..887559800e8 100644 --- a/homeassistant/components/saunum/climate.py +++ b/homeassistant/components/saunum/climate.py @@ -17,13 +17,22 @@ from homeassistant.components.climate import ( HVACAction, HVACMode, ) -from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature +from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, UnitOfTemperature from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from . import LeilSaunaConfigEntry -from .const import DELAYED_REFRESH_SECONDS, DOMAIN +from . import LeilSaunaConfigEntry, LeilSaunaCoordinator +from .const import ( + DEFAULT_PRESET_NAME_TYPE_1, + DEFAULT_PRESET_NAME_TYPE_2, + DEFAULT_PRESET_NAME_TYPE_3, + DELAYED_REFRESH_SECONDS, + DOMAIN, + OPT_PRESET_NAME_TYPE_1, + OPT_PRESET_NAME_TYPE_2, + OPT_PRESET_NAME_TYPE_3, +) from .entity import LeilSaunaEntity PARALLEL_UPDATES = 1 @@ -52,14 +61,51 @@ class LeilSaunaClimate(LeilSaunaEntity, ClimateEntity): """Representation of a Saunum Leil Sauna climate entity.""" _attr_name = None + _attr_translation_key = "saunum_climate" _attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT] _attr_supported_features = ( - ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE + ClimateEntityFeature.TARGET_TEMPERATURE + | ClimateEntityFeature.FAN_MODE + | ClimateEntityFeature.PRESET_MODE ) _attr_temperature_unit = UnitOfTemperature.CELSIUS + _attr_precision = PRECISION_WHOLE + _attr_target_temperature_step = 1.0 _attr_min_temp = MIN_TEMPERATURE _attr_max_temp = MAX_TEMPERATURE _attr_fan_modes = [FAN_OFF, FAN_LOW, FAN_MEDIUM, FAN_HIGH] + _preset_name_map: dict[int, str] + + def __init__(self, coordinator: LeilSaunaCoordinator) -> None: + """Initialize the climate entity.""" + super().__init__(coordinator) + self._update_preset_names() + + def _update_preset_names(self) -> None: + """Update preset names from config entry options.""" + options = self.coordinator.config_entry.options + self._preset_name_map = { + 0: options.get(OPT_PRESET_NAME_TYPE_1, DEFAULT_PRESET_NAME_TYPE_1), + 1: options.get(OPT_PRESET_NAME_TYPE_2, DEFAULT_PRESET_NAME_TYPE_2), + 2: options.get(OPT_PRESET_NAME_TYPE_3, DEFAULT_PRESET_NAME_TYPE_3), + } + self._attr_preset_modes = list(self._preset_name_map.values()) + + async def async_added_to_hass(self) -> None: + """Run when entity about to be added to hass.""" + await super().async_added_to_hass() + self.async_on_remove( + self.coordinator.config_entry.add_update_listener( + self._async_update_listener + ) + ) + + async def _async_update_listener( + self, hass: HomeAssistant, entry: LeilSaunaConfigEntry + ) -> None: + """Handle options update.""" + self._update_preset_names() + self.async_write_ha_state() @property def current_temperature(self) -> float | None: @@ -98,6 +144,14 @@ class LeilSaunaClimate(LeilSaunaEntity, ClimateEntity): else HVACAction.IDLE ) + @property + def preset_mode(self) -> str | None: + """Return the current preset mode.""" + sauna_type = self.coordinator.data.sauna_type + if sauna_type is not None and sauna_type in self._preset_name_map: + return self._preset_name_map[sauna_type] + return self._preset_name_map[0] + async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set new HVAC mode.""" if hvac_mode == HVACMode.HEAT and self.coordinator.data.door_open: @@ -143,10 +197,44 @@ class LeilSaunaClimate(LeilSaunaEntity, ClimateEntity): """Set new fan mode.""" if not self.coordinator.data.session_active: raise ServiceValidationError( - "Cannot change fan mode when sauna session is not active", translation_domain=DOMAIN, translation_key="session_not_active", ) - await self.coordinator.client.async_set_fan_speed(FAN_MODE_TO_SPEED[fan_mode]) + try: + await self.coordinator.client.async_set_fan_speed( + FAN_MODE_TO_SPEED[fan_mode] + ) + except SaunumException as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="set_fan_mode_failed", + ) from err + + await self.coordinator.async_request_refresh() + + async def async_set_preset_mode(self, preset_mode: str) -> None: + """Set new preset mode (sauna type).""" + if self.coordinator.data.session_active: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="preset_session_active", + ) + + # Find the sauna type value from the preset name + sauna_type_value = 0 # Default to type 1 + for type_value, type_name in self._preset_name_map.items(): + if type_name == preset_mode: + sauna_type_value = type_value + break + + try: + await self.coordinator.client.async_set_sauna_type(sauna_type_value) + except SaunumException as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="set_preset_failed", + translation_placeholders={"preset_mode": preset_mode}, + ) from err + await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/saunum/config_flow.py b/homeassistant/components/saunum/config_flow.py index 20ce9f859a7..a13525537bf 100644 --- a/homeassistant/components/saunum/config_flow.py +++ b/homeassistant/components/saunum/config_flow.py @@ -8,11 +8,26 @@ from typing import Any from pysaunum import SaunumClient, SaunumException import voluptuous as vol -from homeassistant.config_entries import SOURCE_USER, ConfigFlow, ConfigFlowResult +from homeassistant.config_entries import ( + SOURCE_USER, + ConfigFlow, + ConfigFlowResult, + OptionsFlow, +) from homeassistant.const import CONF_HOST +from homeassistant.core import callback from homeassistant.helpers import config_validation as cv -from .const import DOMAIN +from . import LeilSaunaConfigEntry +from .const import ( + DEFAULT_PRESET_NAME_TYPE_1, + DEFAULT_PRESET_NAME_TYPE_2, + DEFAULT_PRESET_NAME_TYPE_3, + DOMAIN, + OPT_PRESET_NAME_TYPE_1, + OPT_PRESET_NAME_TYPE_2, + OPT_PRESET_NAME_TYPE_3, +) _LOGGER = logging.getLogger(__name__) @@ -30,14 +45,13 @@ async def validate_input(data: dict[str, Any]) -> None: """ host = data[CONF_HOST] - client = SaunumClient(host=host) + client = await SaunumClient.create(host) try: - await client.connect() # Try to read data to verify communication await client.async_get_data() finally: - client.close() + await client.async_close() class LeilSaunaConfigFlow(ConfigFlow, domain=DOMAIN): @@ -46,6 +60,14 @@ class LeilSaunaConfigFlow(ConfigFlow, domain=DOMAIN): VERSION = 1 MINOR_VERSION = 1 + @staticmethod + @callback + def async_get_options_flow( + config_entry: LeilSaunaConfigEntry, + ) -> LeilSaunaOptionsFlow: + """Get the options flow for this handler.""" + return LeilSaunaOptionsFlow() + async def async_step_reconfigure( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: @@ -83,3 +105,40 @@ class LeilSaunaConfigFlow(ConfigFlow, domain=DOMAIN): data_schema=STEP_USER_DATA_SCHEMA, errors=errors, ) + + +class LeilSaunaOptionsFlow(OptionsFlow): + """Handle options flow for Saunum Leil Sauna Control Unit.""" + + async def async_step_init( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Manage the options for preset mode names.""" + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + return self.async_show_form( + step_id="init", + data_schema=vol.Schema( + { + vol.Optional( + OPT_PRESET_NAME_TYPE_1, + default=self.config_entry.options.get( + OPT_PRESET_NAME_TYPE_1, DEFAULT_PRESET_NAME_TYPE_1 + ), + ): cv.string, + vol.Optional( + OPT_PRESET_NAME_TYPE_2, + default=self.config_entry.options.get( + OPT_PRESET_NAME_TYPE_2, DEFAULT_PRESET_NAME_TYPE_2 + ), + ): cv.string, + vol.Optional( + OPT_PRESET_NAME_TYPE_3, + default=self.config_entry.options.get( + OPT_PRESET_NAME_TYPE_3, DEFAULT_PRESET_NAME_TYPE_3 + ), + ): cv.string, + } + ), + ) diff --git a/homeassistant/components/saunum/const.py b/homeassistant/components/saunum/const.py index 0c841313ad2..beb5589c79c 100644 --- a/homeassistant/components/saunum/const.py +++ b/homeassistant/components/saunum/const.py @@ -7,3 +7,13 @@ DOMAIN: Final = "saunum" DEFAULT_SCAN_INTERVAL: Final = timedelta(seconds=60) DELAYED_REFRESH_SECONDS: Final = timedelta(seconds=3) + +# Option keys for preset names +OPT_PRESET_NAME_TYPE_1: Final = "preset_name_type_1" +OPT_PRESET_NAME_TYPE_2: Final = "preset_name_type_2" +OPT_PRESET_NAME_TYPE_3: Final = "preset_name_type_3" + +# Default preset names (translation keys) +DEFAULT_PRESET_NAME_TYPE_1: Final = "type_1" +DEFAULT_PRESET_NAME_TYPE_2: Final = "type_2" +DEFAULT_PRESET_NAME_TYPE_3: Final = "type_3" diff --git a/homeassistant/components/saunum/diagnostics.py b/homeassistant/components/saunum/diagnostics.py index 2f348dfa50c..5e42e926d33 100644 --- a/homeassistant/components/saunum/diagnostics.py +++ b/homeassistant/components/saunum/diagnostics.py @@ -23,6 +23,7 @@ async def async_get_config_entry_diagnostics( # Build diagnostics data diagnostics_data: dict[str, Any] = { "config": async_redact_data(entry.data, REDACT_CONFIG), + "options": dict(entry.options), "client_info": {"connected": coordinator.client.is_connected}, "coordinator_info": { "last_update_success": coordinator.last_update_success, diff --git a/homeassistant/components/saunum/icons.json b/homeassistant/components/saunum/icons.json index 186f86a6d86..713983b8114 100644 --- a/homeassistant/components/saunum/icons.json +++ b/homeassistant/components/saunum/icons.json @@ -1,5 +1,19 @@ { "entity": { + "climate": { + "saunum_climate": { + "state_attributes": { + "preset_mode": { + "default": "mdi:heat-wave", + "state": { + "type_1": "mdi:numeric-1-box-outline", + "type_2": "mdi:numeric-2-box-outline", + "type_3": "mdi:numeric-3-box-outline" + } + } + } + } + }, "number": { "fan_duration": { "default": "mdi:fan-clock" diff --git a/homeassistant/components/saunum/light.py b/homeassistant/components/saunum/light.py index 179672b4737..30be9924f08 100644 --- a/homeassistant/components/saunum/light.py +++ b/homeassistant/components/saunum/light.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any +from typing import TYPE_CHECKING, Any from pysaunum import SaunumException @@ -15,6 +15,9 @@ from . import LeilSaunaConfigEntry from .const import DOMAIN from .entity import LeilSaunaEntity +if TYPE_CHECKING: + from .coordinator import LeilSaunaCoordinator + PARALLEL_UPDATES = 1 @@ -35,7 +38,7 @@ class LeilSaunaLight(LeilSaunaEntity, LightEntity): _attr_color_mode = ColorMode.ONOFF _attr_supported_color_modes = {ColorMode.ONOFF} - def __init__(self, coordinator) -> None: + def __init__(self, coordinator: LeilSaunaCoordinator) -> None: """Initialize the light entity.""" super().__init__(coordinator) # Override unique_id to differentiate from climate entity diff --git a/homeassistant/components/saunum/manifest.json b/homeassistant/components/saunum/manifest.json index 50ba04dbf6a..65ed36fa79d 100644 --- a/homeassistant/components/saunum/manifest.json +++ b/homeassistant/components/saunum/manifest.json @@ -7,6 +7,6 @@ "integration_type": "device", "iot_class": "local_polling", "loggers": ["pysaunum"], - "quality_scale": "gold", - "requirements": ["pysaunum==0.1.0"] + "quality_scale": "platinum", + "requirements": ["pysaunum==0.3.0"] } diff --git a/homeassistant/components/saunum/number.py b/homeassistant/components/saunum/number.py index cd12df201cc..0a59127ffd6 100644 --- a/homeassistant/components/saunum/number.py +++ b/homeassistant/components/saunum/number.py @@ -133,11 +133,7 @@ class LeilSaunaNumber(LeilSaunaEntity, NumberEntity): except SaunumException as err: raise HomeAssistantError( translation_domain=DOMAIN, - translation_key="set_value_failed", - translation_placeholders={ - "entity": self.entity_description.key, - "value": str(value), - }, + translation_key=f"set_{self.entity_description.key}_failed", ) from err await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/saunum/quality_scale.yaml b/homeassistant/components/saunum/quality_scale.yaml index f681f142467..4a7d29777b4 100644 --- a/homeassistant/components/saunum/quality_scale.yaml +++ b/homeassistant/components/saunum/quality_scale.yaml @@ -73,8 +73,8 @@ rules: comment: Integration controls a single device; no dynamic device discovery needed. # Platinum - async-dependency: todo + async-dependency: done inject-websession: status: exempt comment: Integration uses Modbus TCP protocol and does not make HTTP requests. - strict-typing: todo + strict-typing: done diff --git a/homeassistant/components/saunum/strings.json b/homeassistant/components/saunum/strings.json index e72fad37fa6..945cff52c08 100644 --- a/homeassistant/components/saunum/strings.json +++ b/homeassistant/components/saunum/strings.json @@ -50,6 +50,19 @@ "name": "Thermal cutoff alarm" } }, + "climate": { + "saunum_climate": { + "state_attributes": { + "preset_mode": { + "state": { + "type_1": "Sauna Type 1", + "type_2": "Sauna Type 2", + "type_3": "Sauna Type 3" + } + } + } + } + }, "light": { "light": { "name": "[%key:component::light::title%]" @@ -80,15 +93,24 @@ "door_open": { "message": "Cannot start sauna session when sauna door is open" }, + "preset_session_active": { + "message": "Cannot change preset mode while sauna session is active" + }, "session_active_cannot_change_fan_duration": { - "message": "Cannot change fan duration while session is active" + "message": "Cannot change fan duration while sauna session is active" }, "session_active_cannot_change_sauna_duration": { - "message": "Cannot change sauna duration while session is active" + "message": "Cannot change sauna duration while sauna session is active" }, "session_not_active": { "message": "Cannot change fan mode when sauna session is not active" }, + "set_fan_duration_failed": { + "message": "Failed to set fan duration" + }, + "set_fan_mode_failed": { + "message": "Failed to set fan mode" + }, "set_hvac_mode_failed": { "message": "Failed to set HVAC mode to {hvac_mode}" }, @@ -98,11 +120,31 @@ "set_light_on_failed": { "message": "Failed to turn on light" }, + "set_preset_failed": { + "message": "Failed to set preset to {preset_mode}" + }, + "set_sauna_duration_failed": { + "message": "Failed to set sauna duration" + }, "set_temperature_failed": { "message": "Failed to set temperature to {temperature}" - }, - "set_value_failed": { - "message": "Failed to set {entity} to {value}" + } + }, + "options": { + "step": { + "init": { + "data": { + "preset_name_type_1": "Preset name for sauna type 1", + "preset_name_type_2": "Preset name for sauna type 2", + "preset_name_type_3": "Preset name for sauna type 3" + }, + "data_description": { + "preset_name_type_1": "Custom name for sauna type 1 preset mode", + "preset_name_type_2": "Custom name for sauna type 2 preset mode", + "preset_name_type_3": "Custom name for sauna type 3 preset mode" + }, + "description": "Customize the names of the three sauna type preset modes" + } } } } diff --git a/homeassistant/components/schlage/manifest.json b/homeassistant/components/schlage/manifest.json index eadf5585f30..145978b94bf 100644 --- a/homeassistant/components/schlage/manifest.json +++ b/homeassistant/components/schlage/manifest.json @@ -4,6 +4,7 @@ "codeowners": ["@dknowles2"], "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/schlage", + "integration_type": "hub", "iot_class": "cloud_polling", "requirements": ["pyschlage==2025.9.0"] } diff --git a/homeassistant/components/scrape/sensor.py b/homeassistant/components/scrape/sensor.py index 3e7f416166b..c6682fba5a8 100644 --- a/homeassistant/components/scrape/sensor.py +++ b/homeassistant/components/scrape/sensor.py @@ -142,6 +142,8 @@ async def async_setup_entry( class ScrapeSensor(CoordinatorEntity[ScrapeCoordinator], ManualTriggerSensorEntity): """Representation of a web scrape sensor.""" + _sensor_name: str | None = None + def __init__( self, hass: HomeAssistant, @@ -162,14 +164,26 @@ class ScrapeSensor(CoordinatorEntity[ScrapeCoordinator], ManualTriggerSensorEnti self._value_template = value_template self._attr_native_value = None if not yaml and (unique_id := trigger_entity_config.get(CONF_UNIQUE_ID)): - self._attr_name = None + self._sensor_name = None self._attr_has_entity_name = True self._attr_device_info = DeviceInfo( entry_type=DeviceEntryType.SERVICE, identifiers={(DOMAIN, unique_id)}, manufacturer="Scrape", - name=self.name, + name=self._rendered[CONF_NAME], ) + else: + self._sensor_name = self._rendered.get(CONF_NAME) + + @property + def name(self) -> str | None: + """Return the name of the sensor. + + Override needed because TriggerBaseEntity.name always returns the + rendered name, ignoring _attr_name. When has_entity_name is True, + we need name to return None to use the device name instead. + """ + return self._sensor_name def _extract_value(self) -> Any: """Parse the html extraction in the executor.""" diff --git a/homeassistant/components/sendgrid/notify.py b/homeassistant/components/sendgrid/notify.py index 4dbb95085cb..613329c3658 100644 --- a/homeassistant/components/sendgrid/notify.py +++ b/homeassistant/components/sendgrid/notify.py @@ -4,6 +4,7 @@ from __future__ import annotations from http import HTTPStatus import logging +from typing import Any from sendgrid import SendGridAPIClient import voluptuous as vol @@ -61,7 +62,7 @@ class SendgridNotificationService(BaseNotificationService): self._sg = SendGridAPIClient(self.api_key) - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send an email to a user via SendGrid.""" subject = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) diff --git a/homeassistant/components/sense/manifest.json b/homeassistant/components/sense/manifest.json index 33106f0fd1b..351d3bea7c2 100644 --- a/homeassistant/components/sense/manifest.json +++ b/homeassistant/components/sense/manifest.json @@ -18,6 +18,7 @@ } ], "documentation": "https://www.home-assistant.io/integrations/sense", + "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["sense_energy"], "requirements": ["sense-energy==0.13.8"] diff --git a/homeassistant/components/sensibo/manifest.json b/homeassistant/components/sensibo/manifest.json index 4cadd3f8692..d58bc1a00fe 100644 --- a/homeassistant/components/sensibo/manifest.json +++ b/homeassistant/components/sensibo/manifest.json @@ -12,6 +12,7 @@ "homekit": { "models": ["Sensibo"] }, + "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["pysensibo"], "quality_scale": "platinum", diff --git a/homeassistant/components/sensor/const.py b/homeassistant/components/sensor/const.py index b9ded0dbe7b..be6cc4ea3a5 100644 --- a/homeassistant/components/sensor/const.py +++ b/homeassistant/components/sensor/const.py @@ -63,11 +63,14 @@ from homeassistant.util.unit_conversion import ( InformationConverter, MassConverter, MassVolumeConcentrationConverter, + NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, ReactivePowerConverter, SpeedConverter, + SulphurDioxideConcentrationConverter, TemperatureConverter, TemperatureDeltaConverter, UnitlessRatioConverter, @@ -158,7 +161,7 @@ class SensorDeviceClass(StrEnum): CO = "carbon_monoxide" """Carbon Monoxide gas concentration. - Unit of measurement: `ppm` (parts per million), `mg/m³`, `μg/m³` + Unit of measurement: `ppb` (parts per billion), `ppm` (parts per million), `mg/m³`, `μg/m³` """ CO2 = "carbon_dioxide" @@ -282,7 +285,7 @@ class SensorDeviceClass(StrEnum): NITROGEN_DIOXIDE = "nitrogen_dioxide" """Amount of NO2. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion), `μg/m³` """ NITROGEN_MONOXIDE = "nitrogen_monoxide" @@ -300,7 +303,7 @@ class SensorDeviceClass(StrEnum): OZONE = "ozone" """Amount of O3. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion),`μg/m³` """ PH = "ph" @@ -409,7 +412,7 @@ class SensorDeviceClass(StrEnum): SULPHUR_DIOXIDE = "sulphur_dioxide" """Amount of SO2. - Unit of measurement: `μg/m³` + Unit of measurement: `ppb` (parts per billion), `μg/m³` """ TEMPERATURE = "temperature" @@ -562,6 +565,8 @@ UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = SensorDeviceClass.ENERGY_DISTANCE: EnergyDistanceConverter, SensorDeviceClass.ENERGY_STORAGE: EnergyConverter, SensorDeviceClass.GAS: VolumeConverter, + SensorDeviceClass.NITROGEN_DIOXIDE: NitrogenDioxideConcentrationConverter, + SensorDeviceClass.OZONE: OzoneConcentrationConverter, SensorDeviceClass.POWER: PowerConverter, SensorDeviceClass.POWER_FACTOR: UnitlessRatioConverter, SensorDeviceClass.PRECIPITATION: DistanceConverter, @@ -569,6 +574,7 @@ UNIT_CONVERTERS: dict[SensorDeviceClass | str | None, type[BaseUnitConverter]] = SensorDeviceClass.PRESSURE: PressureConverter, SensorDeviceClass.REACTIVE_ENERGY: ReactiveEnergyConverter, SensorDeviceClass.REACTIVE_POWER: ReactivePowerConverter, + SensorDeviceClass.SULPHUR_DIOXIDE: SulphurDioxideConcentrationConverter, SensorDeviceClass.SPEED: SpeedConverter, SensorDeviceClass.TEMPERATURE: TemperatureConverter, SensorDeviceClass.TEMPERATURE_DELTA: TemperatureDeltaConverter, @@ -595,6 +601,7 @@ DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = { SensorDeviceClass.BATTERY: {PERCENTAGE}, SensorDeviceClass.BLOOD_GLUCOSE_CONCENTRATION: set(UnitOfBloodGlucoseConcentration), SensorDeviceClass.CO: { + CONCENTRATION_PARTS_PER_BILLION, CONCENTRATION_PARTS_PER_MILLION, CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, @@ -628,10 +635,16 @@ DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = { SensorDeviceClass.ILLUMINANCE: {LIGHT_LUX}, SensorDeviceClass.IRRADIANCE: set(UnitOfIrradiance), SensorDeviceClass.MOISTURE: {PERCENTAGE}, - SensorDeviceClass.NITROGEN_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.NITROGEN_DIOXIDE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, SensorDeviceClass.NITROGEN_MONOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.NITROUS_OXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, - SensorDeviceClass.OZONE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.OZONE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, SensorDeviceClass.PH: {None}, SensorDeviceClass.PM1: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, SensorDeviceClass.PM10: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, @@ -657,7 +670,10 @@ DEVICE_CLASS_UNITS: dict[SensorDeviceClass, set[type[StrEnum] | str | None]] = { }, SensorDeviceClass.SOUND_PRESSURE: set(UnitOfSoundPressure), SensorDeviceClass.SPEED: {*UnitOfSpeed, *UnitOfVolumetricFlux}, - SensorDeviceClass.SULPHUR_DIOXIDE: {CONCENTRATION_MICROGRAMS_PER_CUBIC_METER}, + SensorDeviceClass.SULPHUR_DIOXIDE: { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + }, SensorDeviceClass.TEMPERATURE: set(UnitOfTemperature), SensorDeviceClass.TEMPERATURE_DELTA: set(UnitOfTemperature), SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS: { diff --git a/homeassistant/components/shelly/binary_sensor.py b/homeassistant/components/shelly/binary_sensor.py index b85baa1a630..dcaacde9ba9 100644 --- a/homeassistant/components/shelly/binary_sensor.py +++ b/homeassistant/components/shelly/binary_sensor.py @@ -5,7 +5,7 @@ from __future__ import annotations from dataclasses import dataclass from typing import Final, cast -from aioshelly.const import RPC_GENERATIONS +from aioshelly.const import MODEL_FLOOD_G4, RPC_GENERATIONS from homeassistant.components.binary_sensor import ( DOMAIN as BINARY_SENSOR_PLATFORM, @@ -335,6 +335,7 @@ RPC_SENSORS: Final = { device_class=BinarySensorDeviceClass.PROBLEM, entity_category=EntityCategory.DIAGNOSTIC, supported=lambda status: status.get("alarm") is not None, + models={MODEL_FLOOD_G4}, ), "presence_num_objects": RpcBinarySensorDescription( key="presence", diff --git a/homeassistant/components/sinch/notify.py b/homeassistant/components/sinch/notify.py index 8c906d26c23..47f8d6b5a87 100644 --- a/homeassistant/components/sinch/notify.py +++ b/homeassistant/components/sinch/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any from clx.xms.api import MtBatchTextSmsResult from clx.xms.client import Client @@ -67,7 +68,7 @@ class SinchNotificationService(BaseNotificationService): self.sender = config[CONF_SENDER] self.client = Client(config[CONF_SERVICE_PLAN_ID], config[CONF_API_KEY]) - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" targets = kwargs.get(ATTR_TARGET, self.default_recipients) data = kwargs.get(ATTR_DATA) or {} diff --git a/homeassistant/components/siren/condition.py b/homeassistant/components/siren/condition.py new file mode 100644 index 00000000000..2593b00428d --- /dev/null +++ b/homeassistant/components/siren/condition.py @@ -0,0 +1,17 @@ +"""Provides conditions for sirens.""" + +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant +from homeassistant.helpers.condition import Condition, make_entity_state_condition + +from . import DOMAIN + +CONDITIONS: dict[str, type[Condition]] = { + "is_off": make_entity_state_condition(DOMAIN, STATE_OFF), + "is_on": make_entity_state_condition(DOMAIN, STATE_ON), +} + + +async def async_get_conditions(hass: HomeAssistant) -> dict[str, type[Condition]]: + """Return the siren conditions.""" + return CONDITIONS diff --git a/homeassistant/components/siren/conditions.yaml b/homeassistant/components/siren/conditions.yaml new file mode 100644 index 00000000000..41145760d92 --- /dev/null +++ b/homeassistant/components/siren/conditions.yaml @@ -0,0 +1,17 @@ +.condition_common: &condition_common + target: + entity: + domain: siren + fields: + behavior: + required: true + default: any + selector: + select: + translation_key: condition_behavior + options: + - all + - any + +is_off: *condition_common +is_on: *condition_common diff --git a/homeassistant/components/siren/icons.json b/homeassistant/components/siren/icons.json index e43289ffcf0..fa13d285767 100644 --- a/homeassistant/components/siren/icons.json +++ b/homeassistant/components/siren/icons.json @@ -1,4 +1,12 @@ { + "conditions": { + "is_off": { + "condition": "mdi:bullhorn-outline" + }, + "is_on": { + "condition": "mdi:bullhorn" + } + }, "entity_component": { "_": { "default": "mdi:bullhorn" diff --git a/homeassistant/components/siren/strings.json b/homeassistant/components/siren/strings.json index ff78a9a48d8..4c4b186d58d 100644 --- a/homeassistant/components/siren/strings.json +++ b/homeassistant/components/siren/strings.json @@ -1,8 +1,32 @@ { "common": { + "condition_behavior_description": "How the state should match on the targeted sirens.", + "condition_behavior_name": "Behavior", "trigger_behavior_description": "The behavior of the targeted sirens to trigger on.", "trigger_behavior_name": "Behavior" }, + "conditions": { + "is_off": { + "description": "Tests if one or more sirens are off.", + "fields": { + "behavior": { + "description": "[%key:component::siren::common::condition_behavior_description%]", + "name": "[%key:component::siren::common::condition_behavior_name%]" + } + }, + "name": "If a siren is off" + }, + "is_on": { + "description": "Tests if one or more sirens are on.", + "fields": { + "behavior": { + "description": "[%key:component::siren::common::condition_behavior_description%]", + "name": "[%key:component::siren::common::condition_behavior_name%]" + } + }, + "name": "If a siren is on" + } + }, "entity_component": { "_": { "name": "[%key:component::siren::title%]", @@ -18,6 +42,12 @@ } }, "selector": { + "condition_behavior": { + "options": { + "all": "All", + "any": "Any" + } + }, "trigger_behavior": { "options": { "any": "Any", diff --git a/homeassistant/components/sma/config_flow.py b/homeassistant/components/sma/config_flow.py index 7d76fbe0ec9..9e9656eb4b9 100644 --- a/homeassistant/components/sma/config_flow.py +++ b/homeassistant/components/sma/config_flow.py @@ -144,6 +144,51 @@ class SmaConfigFlow(ConfigFlow, domain=DOMAIN): errors=errors, ) + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle reconfiguration of the integration.""" + errors: dict[str, str] = {} + reconf_entry = self._get_reconfigure_entry() + if user_input is not None: + errors, device_info = await self._handle_user_input( + user_input={ + **reconf_entry.data, + **user_input, + } + ) + + if not errors: + await self.async_set_unique_id( + str(device_info["serial"]), raise_on_progress=False + ) + self._abort_if_unique_id_mismatch() + return self.async_update_reload_and_abort( + reconf_entry, + data_updates={ + CONF_HOST: user_input[CONF_HOST], + CONF_SSL: user_input[CONF_SSL], + CONF_VERIFY_SSL: user_input[CONF_VERIFY_SSL], + CONF_GROUP: user_input[CONF_GROUP], + }, + ) + + return self.async_show_form( + step_id="reconfigure", + data_schema=self.add_suggested_values_to_schema( + data_schema=vol.Schema( + { + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_SSL): cv.boolean, + vol.Optional(CONF_VERIFY_SSL): cv.boolean, + vol.Optional(CONF_GROUP): vol.In(GROUPS), + } + ), + suggested_values=user_input or dict(reconf_entry.data), + ), + errors=errors, + ) + async def async_step_reauth( self, entry_data: Mapping[str, Any] ) -> ConfigFlowResult: diff --git a/homeassistant/components/sma/strings.json b/homeassistant/components/sma/strings.json index 07e4047de54..55f2d2512b7 100644 --- a/homeassistant/components/sma/strings.json +++ b/homeassistant/components/sma/strings.json @@ -3,7 +3,9 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]", - "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" + "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", + "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]", + "unique_id_mismatch": "You selected a different SMA device than the one this config entry was configured with, this is not allowed." }, "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", @@ -29,6 +31,16 @@ "description": "The SMA integration needs to re-authenticate your connection details", "title": "[%key:common::config_flow::title::reauth%]" }, + "reconfigure": { + "data": { + "group": "[%key:component::sma::config::step::user::data::group%]", + "host": "[%key:common::config_flow::data::host%]", + "ssl": "[%key:common::config_flow::data::ssl%]", + "verify_ssl": "[%key:common::config_flow::data::verify_ssl%]" + }, + "description": "Use the following form to reconfigure your SMA device.", + "title": "Reconfigure SMA Solar Integration" + }, "user": { "data": { "group": "Group", @@ -44,5 +56,13 @@ "title": "Set up SMA Solar" } } + }, + "selector": { + "group": { + "options": { + "installer": "Installer", + "user": "User" + } + } } } diff --git a/homeassistant/components/smartthings/strings.json b/homeassistant/components/smartthings/strings.json index ed25822ee7f..c04bc67e976 100644 --- a/homeassistant/components/smartthings/strings.json +++ b/homeassistant/components/smartthings/strings.json @@ -18,6 +18,9 @@ "error": { "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "pick_implementation": { "data": { diff --git a/homeassistant/components/spotify/strings.json b/homeassistant/components/spotify/strings.json index 9a2f9069d76..2f88028e28e 100644 --- a/homeassistant/components/spotify/strings.json +++ b/homeassistant/components/spotify/strings.json @@ -16,6 +16,9 @@ "create_entry": { "default": "Successfully authenticated with Spotify." }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "pick_implementation": { "data": { diff --git a/homeassistant/components/sunricher_dali/__init__.py b/homeassistant/components/sunricher_dali/__init__.py index 2137480cea8..893b596e11d 100644 --- a/homeassistant/components/sunricher_dali/__init__.py +++ b/homeassistant/components/sunricher_dali/__init__.py @@ -25,7 +25,12 @@ from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from .const import CONF_SERIAL_NUMBER, DOMAIN, MANUFACTURER from .types import DaliCenterConfigEntry, DaliCenterData -_PLATFORMS: list[Platform] = [Platform.LIGHT, Platform.SCENE] +_PLATFORMS: list[Platform] = [ + Platform.BUTTON, + Platform.LIGHT, + Platform.SCENE, + Platform.SENSOR, +] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sunricher_dali/button.py b/homeassistant/components/sunricher_dali/button.py new file mode 100644 index 00000000000..9ba034924bf --- /dev/null +++ b/homeassistant/components/sunricher_dali/button.py @@ -0,0 +1,63 @@ +"""Support for Sunricher DALI device identify button.""" + +from __future__ import annotations + +import logging + +from PySrDaliGateway import Device +from PySrDaliGateway.helper import is_light_device + +from homeassistant.components.button import ButtonDeviceClass, ButtonEntity +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from .const import DOMAIN, MANUFACTURER +from .entity import DaliDeviceEntity +from .types import DaliCenterConfigEntry + +_LOGGER = logging.getLogger(__name__) + +PARALLEL_UPDATES = 0 + + +async def async_setup_entry( + hass: HomeAssistant, + entry: DaliCenterConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Sunricher DALI button entities from config entry.""" + devices = entry.runtime_data.devices + + async_add_entities( + DaliCenterIdentifyButton(device) + for device in devices + if is_light_device(device.dev_type) + ) + + +class DaliCenterIdentifyButton(DaliDeviceEntity, ButtonEntity): + """Representation of a Sunricher DALI device identify button.""" + + _attr_device_class = ButtonDeviceClass.IDENTIFY + _attr_entity_category = EntityCategory.CONFIG + _attr_name = None + + def __init__(self, device: Device) -> None: + """Initialize the device identify button.""" + super().__init__(device) + self._device = device + self._attr_unique_id = f"{device.unique_id}_identify" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, device.dev_id)}, + name=device.name, + manufacturer=MANUFACTURER, + model=device.model, + via_device=(DOMAIN, device.gw_sn), + ) + + async def async_press(self) -> None: + """Handle button press to identify device.""" + _LOGGER.debug("Identifying device %s", self._device.dev_id) + self._device.identify() diff --git a/homeassistant/components/sunricher_dali/manifest.json b/homeassistant/components/sunricher_dali/manifest.json index 214c822fc01..80524a9bfb1 100644 --- a/homeassistant/components/sunricher_dali/manifest.json +++ b/homeassistant/components/sunricher_dali/manifest.json @@ -11,5 +11,5 @@ "documentation": "https://www.home-assistant.io/integrations/sunricher_dali", "iot_class": "local_push", "quality_scale": "silver", - "requirements": ["PySrDaliGateway==0.18.0"] + "requirements": ["PySrDaliGateway==0.19.3"] } diff --git a/homeassistant/components/sunricher_dali/sensor.py b/homeassistant/components/sunricher_dali/sensor.py new file mode 100644 index 00000000000..19dc58d5168 --- /dev/null +++ b/homeassistant/components/sunricher_dali/sensor.py @@ -0,0 +1,121 @@ +"""Platform for Sunricher DALI sensor entities.""" + +from __future__ import annotations + +import logging + +from PySrDaliGateway import CallbackEventType, Device +from PySrDaliGateway.helper import is_illuminance_sensor +from PySrDaliGateway.types import IlluminanceStatus + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorStateClass, +) +from homeassistant.const import LIGHT_LUX +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from .const import DOMAIN, MANUFACTURER +from .entity import DaliDeviceEntity +from .types import DaliCenterConfigEntry + +_LOGGER = logging.getLogger(__name__) + +PARALLEL_UPDATES = 0 + + +async def async_setup_entry( + hass: HomeAssistant, + entry: DaliCenterConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Sunricher DALI sensor entities from config entry.""" + devices = entry.runtime_data.devices + + entities: list[SensorEntity] = [ + SunricherDaliIlluminanceSensor(device) + for device in devices + if is_illuminance_sensor(device.dev_type) + ] + + if entities: + async_add_entities(entities) + + +class SunricherDaliIlluminanceSensor(DaliDeviceEntity, SensorEntity): + """Representation of a Sunricher DALI Illuminance Sensor.""" + + _attr_device_class = SensorDeviceClass.ILLUMINANCE + _attr_state_class = SensorStateClass.MEASUREMENT + _attr_native_unit_of_measurement = LIGHT_LUX + _attr_name = None + + def __init__(self, device: Device) -> None: + """Initialize the illuminance sensor.""" + super().__init__(device) + self._device = device + self._illuminance_value: float | None = None + self._sensor_enabled: bool = True + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, device.dev_id)}, + name=device.name, + manufacturer=MANUFACTURER, + model=device.model, + via_device=(DOMAIN, device.gw_sn), + ) + + @property + def native_value(self) -> float | None: + """Return the native value, or None if sensor is disabled.""" + if not self._sensor_enabled: + return None + return self._illuminance_value + + async def async_added_to_hass(self) -> None: + """Handle entity addition to Home Assistant.""" + await super().async_added_to_hass() + + self.async_on_remove( + self._device.register_listener( + CallbackEventType.ILLUMINANCE_STATUS, self._handle_illuminance_status + ) + ) + + self.async_on_remove( + self._device.register_listener( + CallbackEventType.SENSOR_ON_OFF, self._handle_sensor_on_off + ) + ) + + self._device.read_status() + + @callback + def _handle_illuminance_status(self, status: IlluminanceStatus) -> None: + """Handle illuminance status updates.""" + illuminance_value = status["illuminance_value"] + is_valid = status["is_valid"] + + if not is_valid: + _LOGGER.debug( + "Illuminance value is not valid for device %s: %s lux", + self._device.dev_id, + illuminance_value, + ) + return + + self._illuminance_value = illuminance_value + self.schedule_update_ha_state() + + @callback + def _handle_sensor_on_off(self, on_off: bool) -> None: + """Handle sensor on/off updates.""" + self._sensor_enabled = on_off + _LOGGER.debug( + "Illuminance sensor enable state for device %s updated to: %s", + self._device.dev_id, + on_off, + ) + self.schedule_update_ha_state() diff --git a/homeassistant/components/switchbot_cloud/__init__.py b/homeassistant/components/switchbot_cloud/__init__.py index dc1bf8e9701..2001bcaf524 100644 --- a/homeassistant/components/switchbot_cloud/__init__.py +++ b/homeassistant/components/switchbot_cloud/__init__.py @@ -185,6 +185,9 @@ async def make_device_data( "Smart Lock Lite", "Smart Lock Pro", "Smart Lock Ultra", + "Smart Lock Vision", + "Smart Lock Vision Pro", + "Smart Lock Pro Wifi", ]: coordinator = await coordinator_for_device( hass, entry, api, device, coordinators_by_id diff --git a/homeassistant/components/switchbot_cloud/binary_sensor.py b/homeassistant/components/switchbot_cloud/binary_sensor.py index 316badc42f7..83dff65ec72 100644 --- a/homeassistant/components/switchbot_cloud/binary_sensor.py +++ b/homeassistant/components/switchbot_cloud/binary_sensor.py @@ -92,6 +92,18 @@ BINARY_SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = { CALIBRATION_DESCRIPTION, DOOR_OPEN_DESCRIPTION, ), + "Smart Lock Vision": ( + CALIBRATION_DESCRIPTION, + DOOR_OPEN_DESCRIPTION, + ), + "Smart Lock Vision Pro": ( + CALIBRATION_DESCRIPTION, + DOOR_OPEN_DESCRIPTION, + ), + "Smart Lock Pro Wifi": ( + CALIBRATION_DESCRIPTION, + DOOR_OPEN_DESCRIPTION, + ), "Curtain": (CALIBRATION_DESCRIPTION,), "Curtain3": (CALIBRATION_DESCRIPTION,), "Roller Shade": (CALIBRATION_DESCRIPTION,), diff --git a/homeassistant/components/switchbot_cloud/lock.py b/homeassistant/components/switchbot_cloud/lock.py index ed852cc7420..191b17c397e 100644 --- a/homeassistant/components/switchbot_cloud/lock.py +++ b/homeassistant/components/switchbot_cloud/lock.py @@ -46,7 +46,7 @@ class SwitchBotCloudLock(SwitchBotCloudEntity, LockEntity): """Set attributes from coordinator data.""" if coord_data := self.coordinator.data: self._attr_is_locked = coord_data["lockState"] == "locked" - if self.__model in LockV2Commands.get_supported_devices(): + if self.__model != "Smart Lock Lite": self._attr_supported_features = LockEntityFeature.OPEN async def async_lock(self, **kwargs: Any) -> None: diff --git a/homeassistant/components/switchbot_cloud/manifest.json b/homeassistant/components/switchbot_cloud/manifest.json index 8a642aaec77..737ddeeef89 100644 --- a/homeassistant/components/switchbot_cloud/manifest.json +++ b/homeassistant/components/switchbot_cloud/manifest.json @@ -13,5 +13,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["switchbot_api"], - "requirements": ["switchbot-api==2.9.0"] + "requirements": ["switchbot-api==2.10.0"] } diff --git a/homeassistant/components/switchbot_cloud/sensor.py b/homeassistant/components/switchbot_cloud/sensor.py index 9f689acc006..b5ff0e88e61 100644 --- a/homeassistant/components/switchbot_cloud/sensor.py +++ b/homeassistant/components/switchbot_cloud/sensor.py @@ -225,6 +225,9 @@ SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = { "Smart Lock Lite": (BATTERY_DESCRIPTION,), "Smart Lock Pro": (BATTERY_DESCRIPTION,), "Smart Lock Ultra": (BATTERY_DESCRIPTION,), + "Smart Lock Vision": (BATTERY_DESCRIPTION,), + "Smart Lock Vision Pro": (BATTERY_DESCRIPTION,), + "Smart Lock Pro Wifi": (BATTERY_DESCRIPTION,), "Relay Switch 2PM": ( RELAY_SWITCH_2PM_POWER_DESCRIPTION, RELAY_SWITCH_2PM_VOLTAGE_DESCRIPTION, diff --git a/homeassistant/components/synology_chat/notify.py b/homeassistant/components/synology_chat/notify.py index 37ea3238a06..a4ae3b1aaa2 100644 --- a/homeassistant/components/synology_chat/notify.py +++ b/homeassistant/components/synology_chat/notify.py @@ -5,6 +5,7 @@ from __future__ import annotations from http import HTTPStatus import json import logging +from typing import Any import requests import voluptuous as vol @@ -51,7 +52,7 @@ class SynologyChatNotificationService(BaseNotificationService): self._resource = resource self._verify_ssl = verify_ssl - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" data = {"text": message} diff --git a/homeassistant/components/syslog/notify.py b/homeassistant/components/syslog/notify.py index dbbada65fb2..96102cc9c0a 100644 --- a/homeassistant/components/syslog/notify.py +++ b/homeassistant/components/syslog/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import syslog +from typing import Any import voluptuous as vol @@ -91,7 +92,7 @@ class SyslogNotificationService(BaseNotificationService): self._option = option self._priority = priority - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to syslog.""" title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) diff --git a/homeassistant/components/tado/manifest.json b/homeassistant/components/tado/manifest.json index 28184e459e9..ec8c53f3572 100644 --- a/homeassistant/components/tado/manifest.json +++ b/homeassistant/components/tado/manifest.json @@ -15,5 +15,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["PyTado"], - "requirements": ["python-tado==0.18.15"] + "requirements": ["python-tado==0.18.16"] } diff --git a/homeassistant/components/tag/__init__.py b/homeassistant/components/tag/__init__.py index 8d42596d3db..8d33705cb67 100644 --- a/homeassistant/components/tag/__init__.py +++ b/homeassistant/components/tag/__init__.py @@ -83,8 +83,8 @@ def _create_entry( DOMAIN, DOMAIN, tag_id, + object_id_base=slugify(name) if name else tag_id, original_name=f"{DEFAULT_NAME} {tag_id}", - suggested_object_id=slugify(name) if name else tag_id, ) if name: return entity_registry.async_update_entity(entry.entity_id, name=name) diff --git a/homeassistant/components/telegram/notify.py b/homeassistant/components/telegram/notify.py index c4a67f67b64..6bd4897939a 100644 --- a/homeassistant/components/telegram/notify.py +++ b/homeassistant/components/telegram/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import voluptuous as vol @@ -77,7 +78,7 @@ class TelegramNotificationService(BaseNotificationService): self._chat_id = chat_id self.hass = hass - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" service_data = {ATTR_TARGET: kwargs.get(ATTR_TARGET, self._chat_id)} data = kwargs.get(ATTR_DATA) @@ -126,7 +127,7 @@ class TelegramNotificationService(BaseNotificationService): self.hass.services.call( TELEGRAM_BOT_DOMAIN, "send_photo", service_data=service_data ) - return None + return if data is not None and ATTR_VIDEO in data: videos = data.get(ATTR_VIDEO) videos = videos if isinstance(videos, list) else [videos] @@ -135,7 +136,7 @@ class TelegramNotificationService(BaseNotificationService): self.hass.services.call( TELEGRAM_BOT_DOMAIN, "send_video", service_data=service_data ) - return None + return if data is not None and ATTR_VOICE in data: voices = data.get(ATTR_VOICE) voices = voices if isinstance(voices, list) else [voices] @@ -144,17 +145,19 @@ class TelegramNotificationService(BaseNotificationService): self.hass.services.call( TELEGRAM_BOT_DOMAIN, "send_voice", service_data=service_data ) - return None + return if data is not None and ATTR_LOCATION in data: service_data.update(data.get(ATTR_LOCATION)) - return self.hass.services.call( + self.hass.services.call( TELEGRAM_BOT_DOMAIN, "send_location", service_data=service_data ) + return if data is not None and ATTR_DOCUMENT in data: service_data.update(data.get(ATTR_DOCUMENT)) - return self.hass.services.call( + self.hass.services.call( TELEGRAM_BOT_DOMAIN, "send_document", service_data=service_data ) + return # Send message @@ -168,6 +171,6 @@ class TelegramNotificationService(BaseNotificationService): TELEGRAM_BOT_DOMAIN, service_data, ) - return self.hass.services.call( + self.hass.services.call( TELEGRAM_BOT_DOMAIN, "send_message", service_data=service_data ) diff --git a/homeassistant/components/telegram_bot/polling.py b/homeassistant/components/telegram_bot/polling.py index b8640c5c005..d2b95cc9d44 100644 --- a/homeassistant/components/telegram_bot/polling.py +++ b/homeassistant/components/telegram_bot/polling.py @@ -24,13 +24,13 @@ async def async_setup_platform( return pollbot -async def process_error(update: object, context: CallbackContext) -> None: +async def process_error(bot: Bot, update: object, context: CallbackContext) -> None: """Telegram bot error handler.""" if context.error: - error_callback(context.error, update) + error_callback(bot, context.error, update) -def error_callback(error: Exception, update: object | None = None) -> None: +def error_callback(bot: Bot, error: Exception, update: object | None = None) -> None: """Log the error.""" try: raise error @@ -39,9 +39,17 @@ def error_callback(error: Exception, update: object | None = None) -> None: pass except TelegramError: if update is not None: - _LOGGER.error('Update "%s" caused error: "%s"', update, error) + _LOGGER.error( + '[%s %s] Update "%s" caused error: "%s"', + bot.username, + bot.id, + update, + error, + ) else: - _LOGGER.error("%s: %s", error.__class__.__name__, error) + _LOGGER.error( + "[%s %s] %s: %s", bot.username, bot.id, error.__class__.__name__, error + ) class PollBot(BaseTelegramBot): @@ -58,7 +66,9 @@ class PollBot(BaseTelegramBot): self.bot = bot self.application = ApplicationBuilder().bot(self.bot).build() self.application.add_handler(TypeHandler(Update, self.handle_update)) - self.application.add_error_handler(process_error) + self.application.add_error_handler( + lambda update, context: process_error(self.bot, update, context) + ) async def shutdown(self) -> None: """Shutdown the app.""" @@ -66,16 +76,18 @@ class PollBot(BaseTelegramBot): async def start_polling(self) -> None: """Start the polling task.""" - _LOGGER.debug("Starting polling") await self.application.initialize() if self.application.updater: - await self.application.updater.start_polling(error_callback=error_callback) + await self.application.updater.start_polling( + error_callback=lambda error: error_callback(self.bot, error, None) + ) await self.application.start() + _LOGGER.info("[%s %s] Started polling", self.bot.username, self.bot.id) async def stop_polling(self) -> None: """Stop the polling task.""" - _LOGGER.debug("Stopping polling") if self.application.updater: await self.application.updater.stop() await self.application.stop() await self.application.shutdown() + _LOGGER.info("[%s %s] Stopped polling", self.bot.username, self.bot.id) diff --git a/homeassistant/components/tesla_fleet/__init__.py b/homeassistant/components/tesla_fleet/__init__.py index 38a5900fcc1..b8b7caf9b71 100644 --- a/homeassistant/components/tesla_fleet/__init__.py +++ b/homeassistant/components/tesla_fleet/__init__.py @@ -4,7 +4,7 @@ from typing import Final from aiohttp.client_exceptions import ClientResponseError import jwt -from tesla_fleet_api import TeslaFleetApi +from tesla_fleet_api import TeslaFleetApi, is_valid_region from tesla_fleet_api.const import Scope from tesla_fleet_api.exceptions import ( InvalidRegion, @@ -14,6 +14,7 @@ from tesla_fleet_api.exceptions import ( OAuthExpired, TeslaFleetError, ) +from tesla_fleet_api.tesla import VehicleFleet from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_ACCESS_TOKEN, CONF_TOKEN, Platform @@ -79,7 +80,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslaFleetConfigEntry) - token = jwt.decode(access_token, options={"verify_signature": False}) scopes: list[Scope] = [Scope(s) for s in token["scp"]] - region: str = token["ou_code"].lower() + region_code = token["ou_code"].lower() + region = region_code if is_valid_region(region_code) else None oauth_session = OAuth2Session(hass, entry, implementation) @@ -131,14 +133,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslaFleetConfigEntry) - product.pop("cached_data", None) vin = product["vin"] signing = product["command_signing"] == "required" + api_vehicle: VehicleFleet if signing: if not tesla.private_key: await tesla.get_private_key(hass.config.path("tesla_fleet.key")) - api = tesla.vehicles.createSigned(vin) + api_vehicle = tesla.vehicles.createSigned(vin) else: - api = tesla.vehicles.createFleet(vin) + api_vehicle = tesla.vehicles.createFleet(vin) coordinator = TeslaFleetVehicleDataCoordinator( - hass, entry, api, product, Scope.VEHICLE_LOCATION in scopes + hass, entry, api_vehicle, product, Scope.VEHICLE_LOCATION in scopes ) await coordinator.async_config_entry_first_refresh() @@ -153,7 +156,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslaFleetConfigEntry) - vehicles.append( TeslaFleetVehicleData( - api=api, + api=api_vehicle, coordinator=coordinator, vin=vin, device=device, @@ -173,14 +176,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslaFleetConfigEntry) - ) continue - api = tesla.energySites.create(site_id) + api_energy = tesla.energySites.create(site_id) - live_coordinator = TeslaFleetEnergySiteLiveCoordinator(hass, entry, api) + live_coordinator = TeslaFleetEnergySiteLiveCoordinator( + hass, entry, api_energy + ) history_coordinator = TeslaFleetEnergySiteHistoryCoordinator( - hass, entry, api + hass, entry, api_energy ) info_coordinator = TeslaFleetEnergySiteInfoCoordinator( - hass, entry, api, product + hass, entry, api_energy, product ) await live_coordinator.async_config_entry_first_refresh() @@ -214,7 +219,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslaFleetConfigEntry) - energysites.append( TeslaFleetEnergyData( - api=api, + api=api_energy, live_coordinator=live_coordinator, history_coordinator=history_coordinator, info_coordinator=info_coordinator, diff --git a/homeassistant/components/tesla_fleet/climate.py b/homeassistant/components/tesla_fleet/climate.py index 2628a9e134f..627f412a673 100644 --- a/homeassistant/components/tesla_fleet/climate.py +++ b/homeassistant/components/tesla_fleet/climate.py @@ -79,7 +79,7 @@ class TeslaFleetClimateEntity(TeslaFleetVehicleEntity, ClimateEntity): self, data: TeslaFleetVehicleData, side: TeslaFleetClimateSide, - scopes: Scope, + scopes: list[Scope], ) -> None: """Initialize the climate.""" @@ -219,7 +219,7 @@ class TeslaFleetCabinOverheatProtectionEntity(TeslaFleetVehicleEntity, ClimateEn def __init__( self, data: TeslaFleetVehicleData, - scopes: Scope, + scopes: list[Scope], ) -> None: """Initialize the cabin overheat climate entity.""" diff --git a/homeassistant/components/tesla_fleet/coordinator.py b/homeassistant/components/tesla_fleet/coordinator.py index 59d1c250703..f875372b8ae 100644 --- a/homeassistant/components/tesla_fleet/coordinator.py +++ b/homeassistant/components/tesla_fleet/coordinator.py @@ -178,13 +178,15 @@ class TeslaFleetEnergySiteLiveCoordinator(DataUpdateCoordinator[dict[str, Any]]) try: data = (await self.api.live_status())["response"] except RateLimited as e: - LOGGER.warning( - "%s rate limited, will retry in %s seconds", - self.name, - e.data.get("after"), - ) - if "after" in e.data: + if isinstance(e.data, dict) and "after" in e.data: + LOGGER.warning( + "%s rate limited, will retry in %s seconds", + self.name, + e.data["after"], + ) self.update_interval = timedelta(seconds=int(e.data["after"])) + else: + LOGGER.warning("%s rate limited, will skip refresh", self.name) return self.data except (InvalidToken, OAuthExpired, LoginRequired) as e: raise ConfigEntryAuthFailed from e @@ -240,13 +242,15 @@ class TeslaFleetEnergySiteHistoryCoordinator(DataUpdateCoordinator[dict[str, Any try: data = (await self.api.energy_history(TeslaEnergyPeriod.DAY))["response"] except RateLimited as e: - LOGGER.warning( - "%s rate limited, will retry in %s seconds", - self.name, - e.data.get("after"), - ) - if "after" in e.data: + if isinstance(e.data, dict) and "after" in e.data: + LOGGER.warning( + "%s rate limited, will retry in %s seconds", + self.name, + e.data["after"], + ) self.update_interval = timedelta(seconds=int(e.data["after"])) + else: + LOGGER.warning("%s rate limited, will skip refresh", self.name) return self.data except (InvalidToken, OAuthExpired, LoginRequired) as e: raise ConfigEntryAuthFailed from e @@ -303,13 +307,15 @@ class TeslaFleetEnergySiteInfoCoordinator(DataUpdateCoordinator[dict[str, Any]]) try: data = (await self.api.site_info())["response"] except RateLimited as e: - LOGGER.warning( - "%s rate limited, will retry in %s seconds", - self.name, - e.data.get("after"), - ) - if "after" in e.data: + if isinstance(e.data, dict) and "after" in e.data: + LOGGER.warning( + "%s rate limited, will retry in %s seconds", + self.name, + e.data["after"], + ) self.update_interval = timedelta(seconds=int(e.data["after"])) + else: + LOGGER.warning("%s rate limited, will skip refresh", self.name) return self.data except (InvalidToken, OAuthExpired, LoginRequired) as e: raise ConfigEntryAuthFailed from e diff --git a/homeassistant/components/tesla_fleet/entity.py b/homeassistant/components/tesla_fleet/entity.py index 583e92595d0..363ae487e84 100644 --- a/homeassistant/components/tesla_fleet/entity.py +++ b/homeassistant/components/tesla_fleet/entity.py @@ -1,7 +1,7 @@ """Tesla Fleet parent entity class.""" from abc import abstractmethod -from typing import Any +from typing import Any, Generic, TypeVar from tesla_fleet_api.const import Scope from tesla_fleet_api.tesla.energysite import EnergySite @@ -21,6 +21,8 @@ from .coordinator import ( from .helpers import wake_up_vehicle from .models import TeslaFleetEnergyData, TeslaFleetVehicleData +_ApiT = TypeVar("_ApiT", bound=VehicleFleet | EnergySite) + class TeslaFleetEntity( CoordinatorEntity[ @@ -28,13 +30,15 @@ class TeslaFleetEntity( | TeslaFleetEnergySiteLiveCoordinator | TeslaFleetEnergySiteHistoryCoordinator | TeslaFleetEnergySiteInfoCoordinator - ] + ], + Generic[_ApiT], ): """Parent class for all TeslaFleet entities.""" _attr_has_entity_name = True read_only: bool scoped: bool + api: _ApiT def __init__( self, @@ -42,7 +46,7 @@ class TeslaFleetEntity( | TeslaFleetEnergySiteLiveCoordinator | TeslaFleetEnergySiteHistoryCoordinator | TeslaFleetEnergySiteInfoCoordinator, - api: VehicleFleet | EnergySite, + api: _ApiT, key: str, ) -> None: """Initialize common aspects of a TeslaFleet entity.""" @@ -100,7 +104,7 @@ class TeslaFleetEntity( ) -class TeslaFleetVehicleEntity(TeslaFleetEntity): +class TeslaFleetVehicleEntity(TeslaFleetEntity[VehicleFleet]): """Parent class for TeslaFleet Vehicle entities.""" _last_update: int = 0 @@ -128,7 +132,7 @@ class TeslaFleetVehicleEntity(TeslaFleetEntity): await wake_up_vehicle(self.vehicle) -class TeslaFleetEnergyLiveEntity(TeslaFleetEntity): +class TeslaFleetEnergyLiveEntity(TeslaFleetEntity[EnergySite]): """Parent class for TeslaFleet Energy Site Live entities.""" def __init__( @@ -143,7 +147,7 @@ class TeslaFleetEnergyLiveEntity(TeslaFleetEntity): super().__init__(data.live_coordinator, data.api, key) -class TeslaFleetEnergyHistoryEntity(TeslaFleetEntity): +class TeslaFleetEnergyHistoryEntity(TeslaFleetEntity[EnergySite]): """Parent class for TeslaFleet Energy Site History entities.""" def __init__( @@ -158,7 +162,7 @@ class TeslaFleetEnergyHistoryEntity(TeslaFleetEntity): super().__init__(data.history_coordinator, data.api, key) -class TeslaFleetEnergyInfoEntity(TeslaFleetEntity): +class TeslaFleetEnergyInfoEntity(TeslaFleetEntity[EnergySite]): """Parent class for TeslaFleet Energy Site Info entities.""" def __init__( @@ -174,7 +178,7 @@ class TeslaFleetEnergyInfoEntity(TeslaFleetEntity): class TeslaFleetWallConnectorEntity( - TeslaFleetEntity, CoordinatorEntity[TeslaFleetEnergySiteLiveCoordinator] + TeslaFleetEntity[EnergySite], CoordinatorEntity[TeslaFleetEnergySiteLiveCoordinator] ): """Parent class for Tesla Fleet Wall Connector entities.""" diff --git a/homeassistant/components/tesla_fleet/manifest.json b/homeassistant/components/tesla_fleet/manifest.json index 5e79a091d93..4a1d49a52dd 100644 --- a/homeassistant/components/tesla_fleet/manifest.json +++ b/homeassistant/components/tesla_fleet/manifest.json @@ -8,5 +8,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["tesla-fleet-api"], - "requirements": ["tesla-fleet-api==1.3.2"] + "requirements": ["tesla-fleet-api==1.4.2"] } diff --git a/homeassistant/components/tesla_fleet/number.py b/homeassistant/components/tesla_fleet/number.py index b4f7e42cafd..9d3787775a4 100644 --- a/homeassistant/components/tesla_fleet/number.py +++ b/homeassistant/components/tesla_fleet/number.py @@ -33,7 +33,7 @@ PARALLEL_UPDATES = 0 class TeslaFleetNumberVehicleEntityDescription(NumberEntityDescription): """Describes TeslaFleet Number entity.""" - func: Callable[[VehicleFleet, float], Awaitable[Any]] + func: Callable[[VehicleFleet, int], Awaitable[Any]] native_min_value: float native_max_value: float min_key: str | None = None @@ -74,19 +74,19 @@ VEHICLE_DESCRIPTIONS: tuple[TeslaFleetNumberVehicleEntityDescription, ...] = ( class TeslaFleetNumberBatteryEntityDescription(NumberEntityDescription): """Describes TeslaFleet Number entity.""" - func: Callable[[EnergySite, float], Awaitable[Any]] + func: Callable[[EnergySite, int], Awaitable[Any]] requires: str | None = None ENERGY_INFO_DESCRIPTIONS: tuple[TeslaFleetNumberBatteryEntityDescription, ...] = ( TeslaFleetNumberBatteryEntityDescription( key="backup_reserve_percent", - func=lambda api, value: api.backup(int(value)), + func=lambda api, value: api.backup(value), requires="components_battery", ), TeslaFleetNumberBatteryEntityDescription( key="off_grid_vehicle_charging_reserve_percent", - func=lambda api, value: api.off_grid_vehicle_charging_reserve(int(value)), + func=lambda api, value: api.off_grid_vehicle_charging_reserve(value), requires="components_off_grid_vehicle_charging_reserve_supported", ), ) diff --git a/homeassistant/components/teslemetry/__init__.py b/homeassistant/components/teslemetry/__init__.py index 5513e2b625c..42d0ac25388 100644 --- a/homeassistant/components/teslemetry/__init__.py +++ b/homeassistant/components/teslemetry/__init__.py @@ -2,9 +2,10 @@ import asyncio from collections.abc import Callable +from functools import partial from typing import Final -from aiohttp import ClientResponseError +from aiohttp import ClientError, ClientResponseError from tesla_fleet_api.const import Scope from tesla_fleet_api.exceptions import ( Forbidden, @@ -26,6 +27,7 @@ from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import config_validation as cv, device_registry as dr from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.config_entry_oauth2_flow import ( + ImplementationUnavailableError, OAuth2Session, async_get_config_entry_implementation, ) @@ -74,28 +76,48 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: return True +async def _get_access_token(oauth_session: OAuth2Session) -> str: + """Get a valid access token, refreshing if necessary.""" + LOGGER.debug( + "Token valid: %s, expires_at: %s", + oauth_session.valid_token, + oauth_session.token.get("expires_at"), + ) + try: + await oauth_session.async_ensure_token_valid() + except ClientResponseError as err: + if err.status == 401: + raise ConfigEntryAuthFailed from err + raise ConfigEntryNotReady from err + except (KeyError, TypeError) as err: + raise ConfigEntryAuthFailed( + translation_domain=DOMAIN, + translation_key="token_data_malformed", + ) from err + except ClientError as err: + raise ConfigEntryNotReady from err + return oauth_session.token[CONF_ACCESS_TOKEN] + + async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) -> bool: """Set up Teslemetry config.""" session = async_get_clientsession(hass) - implementation = await async_get_config_entry_implementation(hass, entry) + try: + implementation = await async_get_config_entry_implementation(hass, entry) + except ImplementationUnavailableError as err: + raise ConfigEntryAuthFailed( + translation_domain=DOMAIN, + translation_key="oauth_implementation_not_available", + ) from err oauth_session = OAuth2Session(hass, entry, implementation) - async def _get_access_token() -> str: - try: - await oauth_session.async_ensure_token_valid() - except ClientResponseError as e: - if e.status == 401: - raise ConfigEntryAuthFailed from e - raise ConfigEntryNotReady from e - token: str = oauth_session.token[CONF_ACCESS_TOKEN] - return token - # Create API connection + access_token = partial(_get_access_token, oauth_session) teslemetry = Teslemetry( session=session, - access_token=_get_access_token, + access_token=access_token, ) try: calls = await asyncio.gather( @@ -135,14 +157,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - # Remove the protobuff 'cached_data' that we do not use to save memory product.pop("cached_data", None) vin = product["vin"] - api = teslemetry.vehicles.create(vin) - coordinator = TeslemetryVehicleDataCoordinator(hass, entry, api, product) + vehicle = teslemetry.vehicles.create(vin) + coordinator = TeslemetryVehicleDataCoordinator( + hass, entry, vehicle, product + ) device = DeviceInfo( identifiers={(DOMAIN, vin)}, manufacturer="Tesla", configuration_url="https://teslemetry.com/console", name=product["display_name"], - model=api.model, + model=vehicle.model, serial_number=vin, ) current_devices.add((DOMAIN, vin)) @@ -151,7 +175,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - if not stream: stream = TeslemetryStream( session, - _get_access_token, + access_token, server=f"{region.lower()}.teslemetry.com", parse_timestamp=True, manual=True, @@ -167,7 +191,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - vehicles.append( TeslemetryVehicleData( - api=api, + api=vehicle, config_entry=entry, coordinator=coordinator, poll=poll, @@ -193,7 +217,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - ) continue - api = teslemetry.energySites.create(site_id) + energy_site = teslemetry.energySites.create(site_id) device = DeviceInfo( identifiers={(DOMAIN, str(site_id))}, manufacturer="Tesla", @@ -209,7 +233,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - # Check live status endpoint works before creating its coordinator try: - live_status = (await api.live_status())["response"] + live_status = (await energy_site.live_status())["response"] except (InvalidToken, Forbidden, SubscriptionRequired) as e: raise ConfigEntryAuthFailed from e except TeslaFleetError as e: @@ -217,19 +241,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - energysites.append( TeslemetryEnergyData( - api=api, + api=energy_site, live_coordinator=( TeslemetryEnergySiteLiveCoordinator( - hass, entry, api, live_status + hass, entry, energy_site, live_status ) if isinstance(live_status, dict) else None ), info_coordinator=TeslemetryEnergySiteInfoCoordinator( - hass, entry, api, product + hass, entry, energy_site, product ), history_coordinator=( - TeslemetryEnergyHistoryCoordinator(hass, entry, api) + TeslemetryEnergyHistoryCoordinator(hass, entry, energy_site) if powerwall else None ), @@ -313,9 +337,9 @@ async def async_migrate_entry( # Convert legacy access token to OAuth tokens using migrate endpoint try: data = await Teslemetry(session, access_token).migrate_to_oauth( - CLIENT_ID, access_token, hass.config.location_name + CLIENT_ID, hass.config.location_name ) - except ClientResponseError as e: + except (ClientError, TypeError) as e: raise ConfigEntryAuthFailed from e # Add auth_implementation for OAuth2 flow compatibility diff --git a/homeassistant/components/teslemetry/config_flow.py b/homeassistant/components/teslemetry/config_flow.py index cdcfaaa2289..b1788df589e 100644 --- a/homeassistant/components/teslemetry/config_flow.py +++ b/homeassistant/components/teslemetry/config_flow.py @@ -18,7 +18,11 @@ from homeassistant.components.application_credentials import ( ClientCredential, async_import_client_credential, ) -from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult +from homeassistant.config_entries import ( + SOURCE_REAUTH, + SOURCE_RECONFIGURE, + ConfigFlowResult, +) from homeassistant.helpers import config_entry_oauth2_flow from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -73,6 +77,11 @@ class OAuth2FlowHandler( return self.async_update_reload_and_abort( self._get_reauth_entry(), data=data ) + if self.source == SOURCE_RECONFIGURE: + self._abort_if_unique_id_mismatch(reason="reconfigure_account_mismatch") + return self.async_update_reload_and_abort( + self._get_reconfigure_entry(), data=data + ) self._abort_if_unique_id_configured() return self.async_create_entry( @@ -121,3 +130,9 @@ class OAuth2FlowHandler( ) return await super().async_step_user() + + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle reconfiguration.""" + return await self.async_step_user() diff --git a/homeassistant/components/teslemetry/coordinator.py b/homeassistant/components/teslemetry/coordinator.py index a73424bdd28..577db30641a 100644 --- a/homeassistant/components/teslemetry/coordinator.py +++ b/homeassistant/components/teslemetry/coordinator.py @@ -7,7 +7,11 @@ from typing import TYPE_CHECKING, Any from tesla_fleet_api.const import TeslaEnergyPeriod, VehicleDataEndpoint from tesla_fleet_api.exceptions import ( + GatewayTimeout, + InvalidResponse, InvalidToken, + RateLimited, + ServiceUnavailable, SubscriptionRequired, TeslaFleetError, ) @@ -23,6 +27,22 @@ if TYPE_CHECKING: from .const import ENERGY_HISTORY_FIELDS, LOGGER from .helpers import flatten +RETRY_EXCEPTIONS = ( + InvalidResponse, + RateLimited, + ServiceUnavailable, + GatewayTimeout, +) + + +def _get_retry_after(e: TeslaFleetError) -> float: + """Calculate wait time from exception.""" + if isinstance(e.data, dict): + if after := e.data.get("after"): + return float(after) + return 10.0 + + VEHICLE_INTERVAL = timedelta(seconds=60) VEHICLE_WAIT = timedelta(minutes=15) ENERGY_LIVE_INTERVAL = timedelta(seconds=30) @@ -69,14 +89,14 @@ class TeslemetryVehicleDataCoordinator(DataUpdateCoordinator[dict[str, Any]]): async def _async_update_data(self) -> dict[str, Any]: """Update vehicle data using Teslemetry API.""" - try: data = (await self.api.vehicle_data(endpoints=ENDPOINTS))["response"] except (InvalidToken, SubscriptionRequired) as e: raise ConfigEntryAuthFailed from e + except RETRY_EXCEPTIONS as e: + raise UpdateFailed(e.message, retry_after=_get_retry_after(e)) from e except TeslaFleetError as e: raise UpdateFailed(e.message) from e - return flatten(data) @@ -111,19 +131,18 @@ class TeslemetryEnergySiteLiveCoordinator(DataUpdateCoordinator[dict[str, Any]]) async def _async_update_data(self) -> dict[str, Any]: """Update energy site data using Teslemetry API.""" - try: data = (await self.api.live_status())["response"] except (InvalidToken, SubscriptionRequired) as e: raise ConfigEntryAuthFailed from e + except RETRY_EXCEPTIONS as e: + raise UpdateFailed(e.message, retry_after=_get_retry_after(e)) from e except TeslaFleetError as e: raise UpdateFailed(e.message) from e - # Convert Wall Connectors from array to dict data["wall_connectors"] = { wc["din"]: wc for wc in (data.get("wall_connectors") or []) } - return data @@ -152,14 +171,14 @@ class TeslemetryEnergySiteInfoCoordinator(DataUpdateCoordinator[dict[str, Any]]) async def _async_update_data(self) -> dict[str, Any]: """Update energy site data using Teslemetry API.""" - try: data = (await self.api.site_info())["response"] except (InvalidToken, SubscriptionRequired) as e: raise ConfigEntryAuthFailed from e + except RETRY_EXCEPTIONS as e: + raise UpdateFailed(e.message, retry_after=_get_retry_after(e)) from e except TeslaFleetError as e: raise UpdateFailed(e.message) from e - return flatten(data) @@ -187,11 +206,12 @@ class TeslemetryEnergyHistoryCoordinator(DataUpdateCoordinator[dict[str, Any]]): async def _async_update_data(self) -> dict[str, Any]: """Update energy site data using Teslemetry API.""" - try: data = (await self.api.energy_history(TeslaEnergyPeriod.DAY))["response"] except (InvalidToken, SubscriptionRequired) as e: raise ConfigEntryAuthFailed from e + except RETRY_EXCEPTIONS as e: + raise UpdateFailed(e.message, retry_after=_get_retry_after(e)) from e except TeslaFleetError as e: raise UpdateFailed(e.message) from e diff --git a/homeassistant/components/teslemetry/manifest.json b/homeassistant/components/teslemetry/manifest.json index dc942335304..d5399a20e30 100644 --- a/homeassistant/components/teslemetry/manifest.json +++ b/homeassistant/components/teslemetry/manifest.json @@ -8,5 +8,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["tesla-fleet-api"], - "requirements": ["tesla-fleet-api==1.3.2", "teslemetry-stream==0.9.0"] + "requirements": ["tesla-fleet-api==1.4.2", "teslemetry-stream==0.9.0"] } diff --git a/homeassistant/components/teslemetry/services.py b/homeassistant/components/teslemetry/services.py index 99d6936ba17..8bbd002897b 100644 --- a/homeassistant/components/teslemetry/services.py +++ b/homeassistant/components/teslemetry/services.py @@ -149,7 +149,7 @@ def async_setup_services(hass: HomeAssistant) -> None: config = async_get_config_for_device(hass, device) vehicle = async_get_vehicle_for_entry(hass, device, config) - time: int | None = None + time: int # Convert time to minutes since minute if "time" in call.data: (hours, minutes, *_seconds) = call.data["time"].split(":") @@ -158,6 +158,8 @@ def async_setup_services(hass: HomeAssistant) -> None: raise ServiceValidationError( translation_domain=DOMAIN, translation_key="set_scheduled_charging_time" ) + else: + time = 0 await handle_vehicle_command( vehicle.api.set_scheduled_charging(enable=call.data["enable"], time=time) @@ -198,6 +200,8 @@ def async_setup_services(hass: HomeAssistant) -> None: translation_domain=DOMAIN, translation_key="set_scheduled_departure_preconditioning", ) + else: + departure_time = 0 # Off peak charging off_peak_charging_enabled = call.data.get(ATTR_OFF_PEAK_CHARGING_ENABLED, False) @@ -214,6 +218,8 @@ def async_setup_services(hass: HomeAssistant) -> None: translation_domain=DOMAIN, translation_key="set_scheduled_departure_off_peak", ) + else: + end_off_peak_time = 0 await handle_vehicle_command( vehicle.api.set_scheduled_departure( @@ -252,9 +258,7 @@ def async_setup_services(hass: HomeAssistant) -> None: vehicle = async_get_vehicle_for_entry(hass, device, config) await handle_vehicle_command( - vehicle.api.set_valet_mode( - call.data.get("enable"), call.data.get("pin", "") - ) + vehicle.api.set_valet_mode(call.data["enable"], call.data["pin"]) ) hass.services.async_register( @@ -276,14 +280,14 @@ def async_setup_services(hass: HomeAssistant) -> None: config = async_get_config_for_device(hass, device) vehicle = async_get_vehicle_for_entry(hass, device, config) - enable = call.data.get("enable") + enable = call.data["enable"] if enable is True: await handle_vehicle_command( - vehicle.api.speed_limit_activate(call.data.get("pin")) + vehicle.api.speed_limit_activate(call.data["pin"]) ) elif enable is False: await handle_vehicle_command( - vehicle.api.speed_limit_deactivate(call.data.get("pin")) + vehicle.api.speed_limit_deactivate(call.data["pin"]) ) hass.services.async_register( @@ -306,7 +310,7 @@ def async_setup_services(hass: HomeAssistant) -> None: site = async_get_energy_site_for_entry(hass, device, config) resp = await handle_command( - site.api.time_of_use_settings(call.data.get(ATTR_TOU_SETTINGS)) + site.api.time_of_use_settings(call.data[ATTR_TOU_SETTINGS]) ) if "error" in resp: raise HomeAssistantError( diff --git a/homeassistant/components/teslemetry/strings.json b/homeassistant/components/teslemetry/strings.json index 84068107768..dfebeb14f23 100644 --- a/homeassistant/components/teslemetry/strings.json +++ b/homeassistant/components/teslemetry/strings.json @@ -33,7 +33,9 @@ "oauth_timeout": "[%key:common::config_flow::abort::oauth2_timeout%]", "oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]", "reauth_account_mismatch": "The reauthentication account does not match the original account", - "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" + "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]", + "reconfigure_account_mismatch": "The reconfiguration account does not match the original account", + "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]" }, "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", @@ -997,7 +999,6 @@ "total_grid_energy_exported": { "name": "Grid exported" }, - "total_home_usage": { "name": "Home usage" }, @@ -1127,6 +1128,21 @@ "no_vehicle_data_for_device": { "message": "No vehicle data for device ID: {device_id}" }, + "oauth_implementation_not_available": { + "message": "OAuth implementation not available, try reauthenticating" + }, + "set_scheduled_charging_time": { + "message": "Scheduled charging time is required when enabling" + }, + "set_scheduled_departure_off_peak": { + "message": "Off-peak charging end time is required when enabling" + }, + "set_scheduled_departure_preconditioning": { + "message": "Preconditioning departure time is required when enabling" + }, + "token_data_malformed": { + "message": "Token data malformed, try reauthenticating" + }, "wake_up_failed": { "message": "Failed to wake up vehicle: {message}" }, diff --git a/homeassistant/components/tessie/manifest.json b/homeassistant/components/tessie/manifest.json index 8cf3bcee263..c12bcd5ce10 100644 --- a/homeassistant/components/tessie/manifest.json +++ b/homeassistant/components/tessie/manifest.json @@ -7,5 +7,5 @@ "integration_type": "hub", "iot_class": "cloud_polling", "loggers": ["tessie", "tesla-fleet-api"], - "requirements": ["tessie-api==0.1.1", "tesla-fleet-api==1.3.2"] + "requirements": ["tessie-api==0.1.1", "tesla-fleet-api==1.4.2"] } diff --git a/homeassistant/components/tibber/__init__.py b/homeassistant/components/tibber/__init__.py index 6bb5c33ceb8..e14a717fcf4 100644 --- a/homeassistant/components/tibber/__init__.py +++ b/homeassistant/components/tibber/__init__.py @@ -33,7 +33,7 @@ from .const import ( from .coordinator import TibberDataAPICoordinator from .services import async_setup_services -PLATFORMS = [Platform.NOTIFY, Platform.SENSOR] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.NOTIFY, Platform.SENSOR] CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN) diff --git a/homeassistant/components/tibber/binary_sensor.py b/homeassistant/components/tibber/binary_sensor.py new file mode 100644 index 00000000000..d1da82618ca --- /dev/null +++ b/homeassistant/components/tibber/binary_sensor.py @@ -0,0 +1,130 @@ +"""Support for Tibber binary sensors.""" + +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +import logging + +import tibber +from tibber.data_api import TibberDevice + +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DOMAIN, TibberConfigEntry +from .coordinator import TibberDataAPICoordinator + +_LOGGER = logging.getLogger(__name__) + + +@dataclass(frozen=True, kw_only=True) +class TibberBinarySensorEntityDescription(BinarySensorEntityDescription): + """Describes Tibber binary sensor entity.""" + + is_on_fn: Callable[[str], bool | None] + + +DATA_API_BINARY_SENSORS: tuple[TibberBinarySensorEntityDescription, ...] = ( + TibberBinarySensorEntityDescription( + key="connector.status", + device_class=BinarySensorDeviceClass.PLUG, + is_on_fn={"connected": True, "disconnected": False}.get, + ), + TibberBinarySensorEntityDescription( + key="charging.status", + device_class=BinarySensorDeviceClass.BATTERY_CHARGING, + is_on_fn={"charging": True, "idle": False}.get, + ), + TibberBinarySensorEntityDescription( + key="onOff", + device_class=BinarySensorDeviceClass.POWER, + is_on_fn={"on": True, "off": False}.get, + ), + TibberBinarySensorEntityDescription( + key="isOnline", + device_class=BinarySensorDeviceClass.CONNECTIVITY, + is_on_fn=lambda v: v.lower() == "true", + entity_category=EntityCategory.DIAGNOSTIC, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: TibberConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up the Tibber binary sensors.""" + coordinator = entry.runtime_data.data_api_coordinator + assert coordinator is not None + + entities: list[TibberDataAPIBinarySensor] = [] + api_binary_sensors = {sensor.key: sensor for sensor in DATA_API_BINARY_SENSORS} + + for device in coordinator.data.values(): + for sensor in device.sensors: + description: TibberBinarySensorEntityDescription | None = ( + api_binary_sensors.get(sensor.id) + ) + if description is None: + continue + entities.append(TibberDataAPIBinarySensor(coordinator, device, description)) + async_add_entities(entities) + + +class TibberDataAPIBinarySensor( + CoordinatorEntity[TibberDataAPICoordinator], BinarySensorEntity +): + """Representation of a Tibber Data API binary sensor.""" + + _attr_has_entity_name = True + entity_description: TibberBinarySensorEntityDescription + + def __init__( + self, + coordinator: TibberDataAPICoordinator, + device: TibberDevice, + entity_description: TibberBinarySensorEntityDescription, + ) -> None: + """Initialize the binary sensor.""" + super().__init__(coordinator) + + self._device_id: str = device.id + self.entity_description = entity_description + + self._attr_unique_id = f"{device.id}_{entity_description.key}" + + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, device.external_id)}, + name=device.name, + manufacturer=device.brand, + model=device.model, + ) + + @property + def available(self) -> bool: + """Return if entity is available.""" + return ( + super().available and self._device_id in self.coordinator.sensors_by_device + ) + + @property + def device(self) -> dict[str, tibber.data_api.Sensor]: + """Return the device sensors.""" + return self.coordinator.sensors_by_device[self._device_id] + + @property + def is_on(self) -> bool | None: + """Return the state of the binary sensor.""" + return self.entity_description.is_on_fn( + str(self.device[self.entity_description.key].value) + ) diff --git a/homeassistant/components/tibber/coordinator.py b/homeassistant/components/tibber/coordinator.py index 84fac8237c0..39fca55238c 100644 --- a/homeassistant/components/tibber/coordinator.py +++ b/homeassistant/components/tibber/coordinator.py @@ -250,6 +250,12 @@ class TibberDataAPICoordinator(DataUpdateCoordinator[dict[str, TibberDevice]]): async def _async_update_data(self) -> dict[str, TibberDevice]: """Fetch the latest device capabilities from the Tibber Data API.""" client = await self._async_get_client() - devices: dict[str, TibberDevice] = await client.update_devices() + try: + devices: dict[str, TibberDevice] = await client.update_devices() + except tibber.exceptions.RateLimitExceededError as err: + raise UpdateFailed( + f"Rate limit exceeded, retry after {err.retry_after} seconds", + retry_after=err.retry_after, + ) from err self._build_sensor_lookup(devices) return devices diff --git a/homeassistant/components/tibber/manifest.json b/homeassistant/components/tibber/manifest.json index 9388d413c04..d44a6b64008 100644 --- a/homeassistant/components/tibber/manifest.json +++ b/homeassistant/components/tibber/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/tibber", "iot_class": "cloud_polling", "loggers": ["tibber"], - "requirements": ["pyTibber==0.34.1"] + "requirements": ["pyTibber==0.35.0"] } diff --git a/homeassistant/components/tibber/sensor.py b/homeassistant/components/tibber/sensor.py index 778e7914d24..5c3632c32d1 100644 --- a/homeassistant/components/tibber/sensor.py +++ b/homeassistant/components/tibber/sensor.py @@ -34,7 +34,7 @@ from homeassistant.const import ( ) from homeassistant.core import Event, HomeAssistant, callback from homeassistant.exceptions import PlatformNotReady -from homeassistant.helpers import device_registry as dr, entity_registry as er +from homeassistant.helpers import entity_registry as er from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.typing import StateType @@ -264,6 +264,15 @@ SENSORS: tuple[SensorEntityDescription, ...] = ( DATA_API_SENSORS: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key="cellular.rssi", + translation_key="cellular_rssi", + device_class=SensorDeviceClass.SIGNAL_STRENGTH, + native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), SensorEntityDescription( key="storage.stateOfCharge", translation_key="storage_state_of_charge", @@ -278,6 +287,254 @@ DATA_API_SENSORS: tuple[SensorEntityDescription, ...] = ( native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, ), + SensorEntityDescription( + key="storage.ratedCapacity", + translation_key="storage_rated_capacity", + device_class=SensorDeviceClass.ENERGY_STORAGE, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="storage.ratedPower", + translation_key="storage_rated_power", + device_class=SensorDeviceClass.POWER, + native_unit_of_measurement=UnitOfPower.WATT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="storage.availableEnergy", + translation_key="storage_available_energy", + device_class=SensorDeviceClass.ENERGY_STORAGE, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.battery.power", + translation_key="power_flow_battery", + device_class=SensorDeviceClass.POWER, + native_unit_of_measurement=UnitOfPower.WATT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.grid.power", + translation_key="power_flow_grid", + device_class=SensorDeviceClass.POWER, + native_unit_of_measurement=UnitOfPower.WATT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.load.power", + translation_key="power_flow_load", + device_class=SensorDeviceClass.POWER, + native_unit_of_measurement=UnitOfPower.WATT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.toGrid", + translation_key="power_flow_to_grid", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.toLoad", + translation_key="power_flow_to_load", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.fromGrid", + translation_key="power_flow_from_grid", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="powerFlow.fromLoad", + translation_key="power_flow_from_load", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="energyFlow.hour.battery.charged", + translation_key="energy_flow_hour_battery_charged", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.hour.battery.discharged", + translation_key="energy_flow_hour_battery_discharged", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.hour.battery.source.grid", + translation_key="energy_flow_hour_battery_source_grid", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.hour.battery.source.load", + translation_key="energy_flow_hour_battery_source_load", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.hour.grid.imported", + translation_key="energy_flow_hour_grid_imported", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.hour.grid.exported", + translation_key="energy_flow_hour_grid_exported", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.hour.load.consumed", + translation_key="energy_flow_hour_load_consumed", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.hour.load.generated", + translation_key="energy_flow_hour_load_generated", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.hour.load.source.battery", + translation_key="energy_flow_hour_load_source_battery", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.hour.load.source.grid", + translation_key="energy_flow_hour_load_source_grid", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.battery.charged", + translation_key="energy_flow_month_battery_charged", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.month.battery.discharged", + translation_key="energy_flow_month_battery_discharged", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.month.battery.source.grid", + translation_key="energy_flow_month_battery_source_grid", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.battery.source.battery", + translation_key="energy_flow_month_battery_source_battery", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.battery.source.load", + translation_key="energy_flow_month_battery_source_load", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.grid.imported", + translation_key="energy_flow_month_grid_imported", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.month.grid.exported", + translation_key="energy_flow_month_grid_exported", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.month.grid.source.battery", + translation_key="energy_flow_month_grid_source_battery", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.grid.source.grid", + translation_key="energy_flow_month_grid_source_grid", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.grid.source.load", + translation_key="energy_flow_month_grid_source_load", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.load.consumed", + translation_key="energy_flow_month_load_consumed", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.month.load.generated", + translation_key="energy_flow_month_load_generated", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="energyFlow.month.load.source.battery", + translation_key="energy_flow_month_load_source_battery", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="energyFlow.month.load.source.grid", + translation_key="energy_flow_month_load_source_grid", + device_class=SensorDeviceClass.ENERGY, + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + state_class=SensorStateClass.TOTAL_INCREASING, + entity_registry_enabled_default=False, + ), SensorEntityDescription( key="range.remaining", translation_key="range_remaining", @@ -351,7 +608,6 @@ async def _async_setup_graphql_sensors( tibber_connection = entry.runtime_data.tibber_connection entity_registry = er.async_get(hass) - device_registry = dr.async_get(hass) coordinator: TibberDataCoordinator | None = None entities: list[TibberSensor] = [] @@ -391,25 +647,6 @@ async def _async_setup_graphql_sensors( ).async_set_updated_data ) - # migrate - old_id = home.info["viewer"]["home"]["meteringPointData"]["consumptionEan"] - if old_id is None: - continue - - # migrate to new device ids - old_entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, old_id) - if old_entity_id is not None: - entity_registry.async_update_entity( - old_entity_id, new_unique_id=home.home_id - ) - - # migrate to new device ids - device_entry = device_registry.async_get_device(identifiers={(DOMAIN, old_id)}) - if device_entry and entry.entry_id in device_entry.config_entries: - device_registry.async_update_device( - device_entry.id, new_identifiers={(DOMAIN, home.home_id)} - ) - async_add_entities(entities) @@ -430,9 +667,6 @@ def _setup_data_api_sensors( for sensor in device.sensors: description: SensorEntityDescription | None = api_sensors.get(sensor.id) if description is None: - _LOGGER.debug( - "Sensor %s not found in DATA_API_SENSORS, skipping", sensor - ) continue entities.append(TibberDataAPISensor(coordinator, device, description)) async_add_entities(entities) diff --git a/homeassistant/components/tibber/strings.json b/homeassistant/components/tibber/strings.json index 4212847379e..1e6011381e3 100644 --- a/homeassistant/components/tibber/strings.json +++ b/homeassistant/components/tibber/strings.json @@ -48,6 +48,9 @@ "average_power": { "name": "Average power" }, + "cellular_rssi": { + "name": "Cellular signal strength" + }, "charging_current_max": { "name": "Maximum allowed charge current" }, @@ -66,6 +69,72 @@ "electricity_price": { "name": "Electricity price" }, + "energy_flow_hour_battery_charged": { + "name": "Battery energy charged this hour" + }, + "energy_flow_hour_battery_discharged": { + "name": "Battery energy discharged this hour" + }, + "energy_flow_hour_battery_source_grid": { + "name": "Battery charged from grid this hour" + }, + "energy_flow_hour_battery_source_load": { + "name": "Battery charged from load this hour" + }, + "energy_flow_hour_grid_exported": { + "name": "Energy exported to grid this hour" + }, + "energy_flow_hour_grid_imported": { + "name": "Energy imported from grid this hour" + }, + "energy_flow_hour_load_consumed": { + "name": "Load energy consumed this hour" + }, + "energy_flow_hour_load_generated": { + "name": "Load energy generated this hour" + }, + "energy_flow_hour_load_source_battery": { + "name": "Load supplied by battery this hour" + }, + "energy_flow_hour_load_source_grid": { + "name": "Load supplied by grid this hour" + }, + "energy_flow_month_battery_charged": { + "name": "Battery energy charged this month" + }, + "energy_flow_month_battery_discharged": { + "name": "Battery energy discharged this month" + }, + "energy_flow_month_battery_source_grid": { + "name": "Battery charged from grid this month" + }, + "energy_flow_month_battery_source_load": { + "name": "Battery charged from load this month" + }, + "energy_flow_month_grid_exported": { + "name": "Energy exported to grid this month" + }, + "energy_flow_month_grid_imported": { + "name": "Energy imported from grid this month" + }, + "energy_flow_month_grid_source_battery": { + "name": "Grid export from battery this month" + }, + "energy_flow_month_grid_source_load": { + "name": "Grid export from load this month" + }, + "energy_flow_month_load_consumed": { + "name": "Load energy consumed this month" + }, + "energy_flow_month_load_generated": { + "name": "Load energy generated this month" + }, + "energy_flow_month_load_source_battery": { + "name": "Load supplied by battery this month" + }, + "energy_flow_month_load_source_grid": { + "name": "Load supplied by grid this month" + }, "estimated_hour_consumption": { "name": "Estimated consumption current hour" }, @@ -102,6 +171,27 @@ "power_factor": { "name": "Power factor" }, + "power_flow_battery": { + "name": "Battery power" + }, + "power_flow_from_grid": { + "name": "Power flow from grid" + }, + "power_flow_from_load": { + "name": "Power flow from load" + }, + "power_flow_grid": { + "name": "Grid power" + }, + "power_flow_load": { + "name": "Load power" + }, + "power_flow_to_grid": { + "name": "Power flow to grid" + }, + "power_flow_to_load": { + "name": "Power flow to load" + }, "power_production": { "name": "Power production" }, @@ -111,6 +201,15 @@ "signal_strength": { "name": "Signal strength" }, + "storage_available_energy": { + "name": "Available energy" + }, + "storage_rated_capacity": { + "name": "Rated capacity" + }, + "storage_rated_power": { + "name": "Rated power" + }, "storage_state_of_charge": { "name": "State of charge" }, diff --git a/homeassistant/components/timer/services.yaml b/homeassistant/components/timer/services.yaml index cc14e6332f1..b5700f8d268 100644 --- a/homeassistant/components/timer/services.yaml +++ b/homeassistant/components/timer/services.yaml @@ -35,6 +35,7 @@ change: required: true example: "00:01:00, 60 or -60" selector: - text: + duration: + allow_negative: true reload: diff --git a/homeassistant/components/tplink_omada/manifest.json b/homeassistant/components/tplink_omada/manifest.json index 7e9cd726f9d..3cf6b78d4c4 100644 --- a/homeassistant/components/tplink_omada/manifest.json +++ b/homeassistant/components/tplink_omada/manifest.json @@ -6,5 +6,6 @@ "documentation": "https://www.home-assistant.io/integrations/tplink_omada", "integration_type": "hub", "iot_class": "local_polling", + "quality_scale": "bronze", "requirements": ["tplink-omada-client==1.5.3"] } diff --git a/homeassistant/components/tuya/__init__.py b/homeassistant/components/tuya/__init__.py index afd0f16b42a..70c517a3cc3 100644 --- a/homeassistant/components/tuya/__init__.py +++ b/homeassistant/components/tuya/__init__.py @@ -165,7 +165,7 @@ class DeviceListener(SharingDeviceListener): self, device: CustomerDevice, updated_status_properties: list[str] | None = None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None = None, ) -> None: """Update device status with optional DP timestamps.""" LOGGER.debug( diff --git a/homeassistant/components/tuya/binary_sensor.py b/homeassistant/components/tuya/binary_sensor.py index f416f33e468..f123c54a5ae 100644 --- a/homeassistant/components/tuya/binary_sensor.py +++ b/homeassistant/components/tuya/binary_sensor.py @@ -471,9 +471,11 @@ class TuyaBinarySensorEntity(TuyaEntity, BinarySensorEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/tuya/climate.py b/homeassistant/components/tuya/climate.py index 583a11a5318..ddfd874c9cb 100644 --- a/homeassistant/components/tuya/climate.py +++ b/homeassistant/components/tuya/climate.py @@ -2,6 +2,7 @@ from __future__ import annotations +import collections from dataclasses import dataclass from typing import Any, Self @@ -38,6 +39,7 @@ from .models import ( DPCodeEnumWrapper, DPCodeIntegerWrapper, ) +from .type_information import EnumTypeInformation TUYA_HVAC_TO_HA = { "auto": HVACMode.HEAT_COOL, @@ -139,6 +141,72 @@ class _SwingModeWrapper(DeviceWrapper): return commands +def _filter_hvac_mode_mappings(tuya_range: list[str]) -> dict[str, HVACMode | None]: + """Filter TUYA_HVAC_TO_HA modes that are not in the range. + + If multiple Tuya modes map to the same HA mode, set the mapping to None to avoid + ambiguity when converting back from HA to Tuya modes. + """ + modes_in_range = { + tuya_mode: TUYA_HVAC_TO_HA.get(tuya_mode) for tuya_mode in tuya_range + } + modes_occurrences = collections.Counter(modes_in_range.values()) + for key, value in modes_in_range.items(): + if value is not None and modes_occurrences[value] > 1: + modes_in_range[key] = None + return modes_in_range + + +class _HvacModeWrapper(DPCodeEnumWrapper): + """Wrapper for managing climate HVACMode.""" + + # Modes that do not map to HVAC modes are ignored (they are handled by PresetWrapper) + + def __init__(self, dpcode: str, type_information: EnumTypeInformation) -> None: + """Init _HvacModeWrapper.""" + super().__init__(dpcode, type_information) + self._mappings = _filter_hvac_mode_mappings(type_information.range) + self.options = [ + ha_mode for ha_mode in self._mappings.values() if ha_mode is not None + ] + + def read_device_status(self, device: CustomerDevice) -> HVACMode | None: + """Read the device status.""" + if (raw := super().read_device_status(device)) not in TUYA_HVAC_TO_HA: + return None + return TUYA_HVAC_TO_HA[raw] + + def _convert_value_to_raw_value( + self, device: CustomerDevice, value: HVACMode + ) -> Any: + """Convert value to raw value.""" + return next( + tuya_mode + for tuya_mode, ha_mode in self._mappings.items() + if ha_mode == value + ) + + +class _PresetWrapper(DPCodeEnumWrapper): + """Wrapper for managing climate preset modes.""" + + # Modes that map to HVAC modes are ignored (they are handled by HVACModeWrapper) + + def __init__(self, dpcode: str, type_information: EnumTypeInformation) -> None: + """Init _PresetWrapper.""" + super().__init__(dpcode, type_information) + mappings = _filter_hvac_mode_mappings(type_information.range) + self.options = [ + tuya_mode for tuya_mode, ha_mode in mappings.items() if ha_mode is None + ] + + def read_device_status(self, device: CustomerDevice) -> str | None: + """Read the device status.""" + if (raw := super().read_device_status(device)) in TUYA_HVAC_TO_HA: + return None + return raw + + @dataclass(frozen=True, kw_only=True) class TuyaClimateEntityDescription(ClimateEntityDescription): """Describe an Tuya climate entity.""" @@ -296,7 +364,10 @@ async def async_setup_entry( (DPCode.FAN_SPEED_ENUM, DPCode.LEVEL, DPCode.WINDSPEED), prefer_function=True, ), - hvac_mode_wrapper=DPCodeEnumWrapper.find_dpcode( + hvac_mode_wrapper=_HvacModeWrapper.find_dpcode( + device, DPCode.MODE, prefer_function=True + ), + preset_wrapper=_PresetWrapper.find_dpcode( device, DPCode.MODE, prefer_function=True ), set_temperature_wrapper=temperature_wrappers[1], @@ -322,7 +393,6 @@ async def async_setup_entry( class TuyaClimateEntity(TuyaEntity, ClimateEntity): """Tuya Climate Device.""" - _hvac_to_tuya: dict[str, str] entity_description: TuyaClimateEntityDescription _attr_name = None @@ -335,7 +405,8 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity): current_humidity_wrapper: DeviceWrapper[int] | None, current_temperature_wrapper: DeviceWrapper[float] | None, fan_mode_wrapper: DeviceWrapper[str] | None, - hvac_mode_wrapper: DeviceWrapper[str] | None, + hvac_mode_wrapper: DeviceWrapper[HVACMode] | None, + preset_wrapper: DeviceWrapper[str] | None, set_temperature_wrapper: DeviceWrapper[float] | None, swing_wrapper: DeviceWrapper[str] | None, switch_wrapper: DeviceWrapper[bool] | None, @@ -351,6 +422,7 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity): self._current_temperature = current_temperature_wrapper self._fan_mode_wrapper = fan_mode_wrapper self._hvac_mode_wrapper = hvac_mode_wrapper + self._preset_wrapper = preset_wrapper self._set_temperature = set_temperature_wrapper self._swing_wrapper = swing_wrapper self._switch_wrapper = switch_wrapper @@ -366,29 +438,24 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity): self._attr_target_temperature_step = set_temperature_wrapper.value_step # Determine HVAC modes - self._attr_hvac_modes: list[HVACMode] = [] - self._hvac_to_tuya = {} + self._attr_hvac_modes = [] if hvac_mode_wrapper: self._attr_hvac_modes = [HVACMode.OFF] - unknown_hvac_modes: list[str] = [] - for tuya_mode in hvac_mode_wrapper.options: - if tuya_mode in TUYA_HVAC_TO_HA: - ha_mode = TUYA_HVAC_TO_HA[tuya_mode] - self._hvac_to_tuya[ha_mode] = tuya_mode - self._attr_hvac_modes.append(ha_mode) - else: - unknown_hvac_modes.append(tuya_mode) + for mode in hvac_mode_wrapper.options: + self._attr_hvac_modes.append(HVACMode(mode)) - if unknown_hvac_modes: # Tuya modes are presets instead of hvac_modes - self._attr_hvac_modes.append(description.switch_only_hvac_mode) - self._attr_preset_modes = unknown_hvac_modes - self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE elif switch_wrapper: self._attr_hvac_modes = [ HVACMode.OFF, description.switch_only_hvac_mode, ] + # Determine preset modes (ignore if empty options) + if preset_wrapper and preset_wrapper.options: + self._attr_hvac_modes.append(description.switch_only_hvac_mode) + self._attr_preset_modes = preset_wrapper.options + self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE + # Determine dpcode to use for setting the humidity if target_humidity_wrapper: self._attr_supported_features |= ClimateEntityFeature.TARGET_HUMIDITY @@ -419,17 +486,15 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity): self.device, hvac_mode != HVACMode.OFF ) ) - if self._hvac_mode_wrapper and hvac_mode in self._hvac_to_tuya: + if self._hvac_mode_wrapper and hvac_mode in self._hvac_mode_wrapper.options: commands.extend( - self._hvac_mode_wrapper.get_update_commands( - self.device, self._hvac_to_tuya[hvac_mode] - ) + self._hvac_mode_wrapper.get_update_commands(self.device, hvac_mode) ) await self._async_send_commands(commands) async def async_set_preset_mode(self, preset_mode: str) -> None: """Set new target preset mode.""" - await self._async_send_wrapper_updates(self._hvac_mode_wrapper, preset_mode) + await self._async_send_wrapper_updates(self._preset_wrapper, preset_mode) async def async_set_fan_mode(self, fan_mode: str) -> None: """Set new target fan mode.""" @@ -484,21 +549,12 @@ class TuyaClimateEntity(TuyaEntity, ClimateEntity): return None # If we do have a mode wrapper, check if the mode maps to an HVAC mode. - if (hvac_status := self._read_wrapper(self._hvac_mode_wrapper)) is None: - return None - return TUYA_HVAC_TO_HA.get(hvac_status) + return self._read_wrapper(self._hvac_mode_wrapper) @property def preset_mode(self) -> str | None: """Return preset mode.""" - if self._hvac_mode_wrapper is None: - return None - - mode = self._read_wrapper(self._hvac_mode_wrapper) - if mode in TUYA_HVAC_TO_HA: - return None - - return mode + return self._read_wrapper(self._preset_wrapper) @property def fan_mode(self) -> str | None: diff --git a/homeassistant/components/tuya/entity.py b/homeassistant/components/tuya/entity.py index 49848422c04..c6cc76c22cf 100644 --- a/homeassistant/components/tuya/entity.py +++ b/homeassistant/components/tuya/entity.py @@ -57,7 +57,7 @@ class TuyaEntity(Entity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: self.async_write_ha_state() diff --git a/homeassistant/components/tuya/event.py b/homeassistant/components/tuya/event.py index de754f15a47..4ac2c269fa3 100644 --- a/homeassistant/components/tuya/event.py +++ b/homeassistant/components/tuya/event.py @@ -218,10 +218,10 @@ class TuyaEventEntity(TuyaEntity, EventEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: if self._dpcode_wrapper.skip_update( - self.device, updated_status_properties + self.device, updated_status_properties, dp_timestamps ) or not (event_data := self._dpcode_wrapper.read_device_status(self.device)): return diff --git a/homeassistant/components/tuya/models.py b/homeassistant/components/tuya/models.py index a7234e36882..747a5676e00 100644 --- a/homeassistant/components/tuya/models.py +++ b/homeassistant/components/tuya/models.py @@ -31,7 +31,10 @@ class DeviceWrapper[T]: options: list[str] def skip_update( - self, device: CustomerDevice, updated_status_properties: list[str] | None + self, + device: CustomerDevice, + updated_status_properties: list[str] | None, + dp_timestamps: dict[str, int] | None, ) -> bool: """Determine if the wrapper should skip an update. @@ -62,7 +65,10 @@ class DPCodeWrapper(DeviceWrapper): self.dpcode = dpcode def skip_update( - self, device: CustomerDevice, updated_status_properties: list[str] | None + self, + device: CustomerDevice, + updated_status_properties: list[str] | None, + dp_timestamps: dict[str, int] | None, ) -> bool: """Determine if the wrapper should skip an update. diff --git a/homeassistant/components/tuya/number.py b/homeassistant/components/tuya/number.py index 13ab3472aa8..a8534f4c489 100644 --- a/homeassistant/components/tuya/number.py +++ b/homeassistant/components/tuya/number.py @@ -554,10 +554,12 @@ class TuyaNumberEntity(TuyaEntity, NumberEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/tuya/select.py b/homeassistant/components/tuya/select.py index ac61b46e919..8e884d47cf7 100644 --- a/homeassistant/components/tuya/select.py +++ b/homeassistant/components/tuya/select.py @@ -410,10 +410,12 @@ class TuyaSelectEntity(TuyaEntity, SelectEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/tuya/sensor.py b/homeassistant/components/tuya/sensor.py index f5e51a28090..0c4a120c5cf 100644 --- a/homeassistant/components/tuya/sensor.py +++ b/homeassistant/components/tuya/sensor.py @@ -1853,9 +1853,11 @@ class TuyaSensorEntity(TuyaEntity, SensorEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/tuya/siren.py b/homeassistant/components/tuya/siren.py index 4adc42adead..4bd803b19a0 100644 --- a/homeassistant/components/tuya/siren.py +++ b/homeassistant/components/tuya/siren.py @@ -110,10 +110,12 @@ class TuyaSirenEntity(TuyaEntity, SirenEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/tuya/switch.py b/homeassistant/components/tuya/switch.py index 50b4712bc2b..dce5fec0ef0 100644 --- a/homeassistant/components/tuya/switch.py +++ b/homeassistant/components/tuya/switch.py @@ -1043,10 +1043,12 @@ class TuyaSwitchEntity(TuyaEntity, SwitchEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/tuya/valve.py b/homeassistant/components/tuya/valve.py index be2bd905bb1..01bf0f054f6 100644 --- a/homeassistant/components/tuya/valve.py +++ b/homeassistant/components/tuya/valve.py @@ -140,10 +140,12 @@ class TuyaValveEntity(TuyaEntity, ValveEntity): async def _handle_state_update( self, updated_status_properties: list[str] | None, - dp_timestamps: dict | None = None, + dp_timestamps: dict[str, int] | None, ) -> None: """Handle state update, only if this entity's dpcode was actually updated.""" - if self._dpcode_wrapper.skip_update(self.device, updated_status_properties): + if self._dpcode_wrapper.skip_update( + self.device, updated_status_properties, dp_timestamps + ): return self.async_write_ha_state() diff --git a/homeassistant/components/twilio_call/notify.py b/homeassistant/components/twilio_call/notify.py index 4c432e0aeb5..bcea6d6fb82 100644 --- a/homeassistant/components/twilio_call/notify.py +++ b/homeassistant/components/twilio_call/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import urllib from twilio.base.exceptions import TwilioRestException @@ -50,7 +51,7 @@ class TwilioCallNotificationService(BaseNotificationService): self.client = twilio_client self.from_number = from_number - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Call to specified target users.""" if not (targets := kwargs.get(ATTR_TARGET)): _LOGGER.warning("At least 1 target is required") diff --git a/homeassistant/components/twilio_sms/notify.py b/homeassistant/components/twilio_sms/notify.py index a3f824f375f..24527fdaf53 100644 --- a/homeassistant/components/twilio_sms/notify.py +++ b/homeassistant/components/twilio_sms/notify.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +from typing import Any import voluptuous as vol @@ -56,7 +57,7 @@ class TwilioSMSNotificationService(BaseNotificationService): self.client = twilio_client self.from_number = from_number - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Send SMS to specified target user cell.""" targets = kwargs.get(ATTR_TARGET) data = kwargs.get(ATTR_DATA) or {} diff --git a/homeassistant/components/twitch/strings.json b/homeassistant/components/twitch/strings.json index 4a3566325a5..8c18fad01ce 100644 --- a/homeassistant/components/twitch/strings.json +++ b/homeassistant/components/twitch/strings.json @@ -10,6 +10,9 @@ "unknown": "[%key:common::config_flow::error::unknown%]", "wrong_account": "Wrong account: Please authenticate with {username}." }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "reauth_confirm": { "description": "The Twitch integration needs to re-authenticate your account", diff --git a/homeassistant/components/twitter/notify.py b/homeassistant/components/twitter/notify.py index f94bcd54459..7799cfbb85e 100644 --- a/homeassistant/components/twitter/notify.py +++ b/homeassistant/components/twitter/notify.py @@ -9,6 +9,7 @@ import json import logging import mimetypes import os +from typing import Any from TwitterAPI import TwitterAPI import voluptuous as vol @@ -79,7 +80,7 @@ class TwitterNotificationService(BaseNotificationService): consumer_key, consumer_secret, access_token_key, access_token_secret ) - def send_message(self, message="", **kwargs): + def send_message(self, message: str = "", **kwargs: Any) -> None: """Tweet a message, optionally with media.""" data = kwargs.get(ATTR_DATA) targets = kwargs.get(ATTR_TARGET) diff --git a/homeassistant/components/unifiprotect/manifest.json b/homeassistant/components/unifiprotect/manifest.json index 5ba6b39bcd9..b21340d9e4e 100644 --- a/homeassistant/components/unifiprotect/manifest.json +++ b/homeassistant/components/unifiprotect/manifest.json @@ -41,7 +41,7 @@ "iot_class": "local_push", "loggers": ["uiprotect", "unifi_discovery"], "quality_scale": "platinum", - "requirements": ["uiprotect==8.0.0", "unifi-discovery==1.2.0"], + "requirements": ["uiprotect==10.0.0", "unifi-discovery==1.2.0"], "ssdp": [ { "manufacturer": "Ubiquiti Networks", diff --git a/homeassistant/components/unifiprotect/number.py b/homeassistant/components/unifiprotect/number.py index 26ee052f6dd..ab21d0a8670 100644 --- a/homeassistant/components/unifiprotect/number.py +++ b/homeassistant/components/unifiprotect/number.py @@ -5,9 +5,11 @@ from __future__ import annotations from collections.abc import Sequence from dataclasses import dataclass from datetime import timedelta +import logging from uiprotect.data import ( Camera, + Chime, Doorlock, Light, ModelType, @@ -30,6 +32,8 @@ from .entity import ( ) from .utils import async_ufp_instance_command +_LOGGER = logging.getLogger(__name__) + PARALLEL_UPDATES = 0 @@ -245,6 +249,51 @@ _MODEL_DESCRIPTIONS: dict[ModelType, Sequence[ProtectEntityDescription]] = { } +def _async_chime_ring_volume_entities( + data: ProtectData, + chime: Chime, +) -> list[ChimeRingVolumeNumber]: + """Generate ring volume entities for each paired camera on a chime.""" + entities: list[ChimeRingVolumeNumber] = [] + + if not chime.is_adopted_by_us: + return entities + + auth_user = data.api.bootstrap.auth_user + if not chime.can_write(auth_user): + return entities + + for ring_setting in chime.ring_settings: + camera = data.api.bootstrap.cameras.get(ring_setting.camera_id) + if camera is None: + _LOGGER.debug( + "Camera %s not found for chime %s ring volume", + ring_setting.camera_id, + chime.display_name, + ) + continue + entities.append(ChimeRingVolumeNumber(data, chime, camera)) + + return entities + + +def _async_all_chime_ring_volume_entities( + data: ProtectData, + chime: Chime | None = None, +) -> list[ChimeRingVolumeNumber]: + """Generate all ring volume entities for chimes.""" + entities: list[ChimeRingVolumeNumber] = [] + + if chime is not None: + return _async_chime_ring_volume_entities(data, chime) + + for device in data.get_by_types({ModelType.CHIME}): + if isinstance(device, Chime): + entities.extend(_async_chime_ring_volume_entities(data, device)) + + return entities + + async def async_setup_entry( hass: HomeAssistant, entry: UFPConfigEntry, @@ -255,23 +304,26 @@ async def async_setup_entry( @callback def _add_new_device(device: ProtectAdoptableDeviceModel) -> None: - async_add_entities( - async_all_device_entities( - data, - ProtectNumbers, - model_descriptions=_MODEL_DESCRIPTIONS, - ufp_device=device, - ) - ) - - data.async_subscribe_adopt(_add_new_device) - async_add_entities( - async_all_device_entities( + entities = async_all_device_entities( data, ProtectNumbers, model_descriptions=_MODEL_DESCRIPTIONS, + ufp_device=device, ) + # Add ring volume entities for chimes + if isinstance(device, Chime): + entities += _async_all_chime_ring_volume_entities(data, device) + async_add_entities(entities) + + data.async_subscribe_adopt(_add_new_device) + entities = async_all_device_entities( + data, + ProtectNumbers, + model_descriptions=_MODEL_DESCRIPTIONS, ) + # Add ring volume entities for all chimes + entities += _async_all_chime_ring_volume_entities(data) + async_add_entities(entities) class ProtectNumbers(ProtectDeviceEntity, NumberEntity): @@ -302,3 +354,62 @@ class ProtectNumbers(ProtectDeviceEntity, NumberEntity): async def async_set_native_value(self, value: float) -> None: """Set new value.""" await self.entity_description.ufp_set(self.device, value) + + +class ChimeRingVolumeNumber(ProtectDeviceEntity, NumberEntity): + """A UniFi Protect Number Entity for ring volume per camera on a chime.""" + + device: Chime + _state_attrs = ("_attr_available", "_attr_native_value") + _attr_native_max_value: float = 100 + _attr_native_min_value: float = 0 + _attr_native_step: float = 1 + _attr_native_unit_of_measurement = PERCENTAGE + _attr_entity_category = EntityCategory.CONFIG + + def __init__( + self, + data: ProtectData, + chime: Chime, + camera: Camera, + ) -> None: + """Initialize the ring volume number entity.""" + self._camera_id = camera.id + # Use chime MAC and camera ID for unique ID + super().__init__(data, chime) + self._attr_unique_id = f"{chime.mac}_ring_volume_{camera.id}" + self._attr_translation_key = "chime_ring_volume" + self._attr_translation_placeholders = {"camera_name": camera.display_name} + # BaseProtectEntity sets _attr_name = None when no description is passed, + # which prevents translation_key from being used. Delete to enable translations. + del self._attr_name + + @callback + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: + """Update entity from protect device.""" + super()._async_update_device_from_protect(device) + self._attr_native_value = self._get_ring_volume() + + def _get_ring_volume(self) -> int | None: + """Get the ring volume for this camera from the chime's ring settings.""" + for ring_setting in self.device.ring_settings: + if ring_setting.camera_id == self._camera_id: + return ring_setting.volume + return None + + @property + def available(self) -> bool: + """Return if entity is available.""" + # Entity is unavailable if the camera is no longer paired with the chime + return super().available and self._get_ring_volume() is not None + + @async_ufp_instance_command + async def async_set_native_value(self, value: float) -> None: + """Set new ring volume value.""" + camera = self.data.api.bootstrap.cameras.get(self._camera_id) + if camera is None: + _LOGGER.warning( + "Cannot set ring volume: camera %s not found", self._camera_id + ) + return + await self.device.set_volume_for_camera_public(camera, int(value)) diff --git a/homeassistant/components/unifiprotect/strings.json b/homeassistant/components/unifiprotect/strings.json index 0ebe3b5dd14..0d9812abcd3 100644 --- a/homeassistant/components/unifiprotect/strings.json +++ b/homeassistant/components/unifiprotect/strings.json @@ -323,6 +323,9 @@ "chime_duration": { "name": "Chime duration" }, + "chime_ring_volume": { + "name": "Ring volume ({camera_name})" + }, "doorbell_ring_volume": { "name": "Doorbell ring volume" }, diff --git a/homeassistant/components/utility_meter/__init__.py b/homeassistant/components/utility_meter/__init__.py index a79881d3983..834e148a136 100644 --- a/homeassistant/components/utility_meter/__init__.py +++ b/homeassistant/components/utility_meter/__init__.py @@ -9,8 +9,8 @@ import voluptuous as vol from homeassistant.components.select import DOMAIN as SELECT_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ATTR_ENTITY_ID, CONF_NAME, CONF_UNIQUE_ID, Platform -from homeassistant.core import HomeAssistant, split_entity_id +from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID, Platform +from homeassistant.core import HomeAssistant from homeassistant.helpers import ( config_validation as cv, discovery, @@ -20,7 +20,6 @@ from homeassistant.helpers.device import ( async_entity_id_to_device_id, async_remove_stale_devices_links_keep_entity_device, ) -from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.helper_integration import ( async_handle_source_entity_changes, async_remove_helper_config_entry_from_source_device, @@ -44,9 +43,8 @@ from .const import ( DATA_UTILITY, DOMAIN, METER_TYPES, - SERVICE_RESET, - SIGNAL_RESET_METER, ) +from .services import async_setup_services _LOGGER = logging.getLogger(__name__) @@ -120,27 +118,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up an Utility Meter.""" hass.data[DATA_UTILITY] = {} - async def async_reset_meters(service_call): - """Reset all sensors of a meter.""" - meters = service_call.data["entity_id"] - - for meter in meters: - _LOGGER.debug("resetting meter %s", meter) - domain, entity = split_entity_id(meter) - # backward compatibility up to 2022.07: - if domain == DOMAIN: - async_dispatcher_send( - hass, SIGNAL_RESET_METER, f"{SELECT_DOMAIN}.{entity}" - ) - else: - async_dispatcher_send(hass, SIGNAL_RESET_METER, meter) - - hass.services.async_register( - DOMAIN, - SERVICE_RESET, - async_reset_meters, - vol.Schema({ATTR_ENTITY_ID: vol.All(cv.ensure_list, [cv.entity_id])}), - ) + async_setup_services(hass) if DOMAIN not in config: return True @@ -250,7 +228,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: else: # Create tariff selection + one meter sensor for each tariff entity_entry = entity_registry.async_get_or_create( - Platform.SELECT, DOMAIN, entry.entry_id, suggested_object_id=entry.title + Platform.SELECT, DOMAIN, entry.entry_id, object_id_base=entry.title ) hass.data[DATA_UTILITY][entry.entry_id][CONF_TARIFF_ENTITY] = ( entity_entry.entity_id diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index 5ab476edecb..071488dc68b 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -688,7 +688,7 @@ class UtilityMeterSensor(RestoreSensor): self._collecting = None @property - def device_class(self): + def device_class(self) -> SensorDeviceClass | None: """Return the device class of the sensor.""" if self._input_device_class is not None: return self._input_device_class @@ -700,7 +700,7 @@ class UtilityMeterSensor(RestoreSensor): return None @property - def state_class(self): + def state_class(self) -> SensorStateClass: """Return the device class of the sensor.""" return ( SensorStateClass.TOTAL diff --git a/homeassistant/components/utility_meter/services.py b/homeassistant/components/utility_meter/services.py new file mode 100644 index 00000000000..ce2755f46ce --- /dev/null +++ b/homeassistant/components/utility_meter/services.py @@ -0,0 +1,43 @@ +"""Support for tracking consumption over given periods of time.""" + +import logging + +import voluptuous as vol + +from homeassistant.components.select import DOMAIN as SELECT_DOMAIN +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.core import HomeAssistant, ServiceCall, callback, split_entity_id +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.dispatcher import async_dispatcher_send + +from .const import DOMAIN, SERVICE_RESET, SIGNAL_RESET_METER + +_LOGGER = logging.getLogger(__name__) + + +async def async_reset_meters(service_call: ServiceCall) -> None: + """Reset all sensors of a meter.""" + meters = service_call.data["entity_id"] + + for meter in meters: + _LOGGER.debug("resetting meter %s", meter) + domain, entity = split_entity_id(meter) + # backward compatibility up to 2022.07: + if domain == DOMAIN: + async_dispatcher_send( + service_call.hass, SIGNAL_RESET_METER, f"{SELECT_DOMAIN}.{entity}" + ) + else: + async_dispatcher_send(service_call.hass, SIGNAL_RESET_METER, meter) + + +@callback +def async_setup_services(hass: HomeAssistant) -> None: + """Set up the services.""" + + hass.services.async_register( + DOMAIN, + SERVICE_RESET, + async_reset_meters, + vol.Schema({ATTR_ENTITY_ID: vol.All(cv.ensure_list, [cv.entity_id])}), + ) diff --git a/homeassistant/components/vacuum/icons.json b/homeassistant/components/vacuum/icons.json index 7ccf5c4715a..73027b0ea8f 100644 --- a/homeassistant/components/vacuum/icons.json +++ b/homeassistant/components/vacuum/icons.json @@ -44,7 +44,7 @@ }, "triggers": { "docked": { - "trigger": "mdi:home-import-outline" + "trigger": "mdi:home-outline" }, "errored": { "trigger": "mdi:alert-circle-outline" @@ -54,6 +54,9 @@ }, "started_cleaning": { "trigger": "mdi:play" + }, + "started_returning": { + "trigger": "mdi:home-import-outline" } } } diff --git a/homeassistant/components/vacuum/strings.json b/homeassistant/components/vacuum/strings.json index 44875978e4a..6519d28cb50 100644 --- a/homeassistant/components/vacuum/strings.json +++ b/homeassistant/components/vacuum/strings.json @@ -113,7 +113,7 @@ "title": "Vacuum", "triggers": { "docked": { - "description": "Triggers after one or more vacuums return to dock.", + "description": "Triggers after one or more vacuums have returned to dock.", "fields": { "behavior": { "description": "[%key:component::vacuum::common::trigger_behavior_description%]", @@ -151,6 +151,16 @@ } }, "name": "Vacuum cleaner started cleaning" + }, + "started_returning": { + "description": "Triggers after one or more vacuums start returning to dock.", + "fields": { + "behavior": { + "description": "[%key:component::vacuum::common::trigger_behavior_description%]", + "name": "[%key:component::vacuum::common::trigger_behavior_name%]" + } + }, + "name": "Vacuum cleaner started returning to dock" } } } diff --git a/homeassistant/components/vacuum/trigger.py b/homeassistant/components/vacuum/trigger.py index 50ca8af7d47..cbd5d06df0a 100644 --- a/homeassistant/components/vacuum/trigger.py +++ b/homeassistant/components/vacuum/trigger.py @@ -12,6 +12,9 @@ TRIGGERS: dict[str, type[Trigger]] = { "started_cleaning": make_entity_target_state_trigger( DOMAIN, VacuumActivity.CLEANING ), + "started_returning": make_entity_target_state_trigger( + DOMAIN, VacuumActivity.RETURNING + ), } diff --git a/homeassistant/components/vacuum/triggers.yaml b/homeassistant/components/vacuum/triggers.yaml index d4f5fa582b8..e0266db92bc 100644 --- a/homeassistant/components/vacuum/triggers.yaml +++ b/homeassistant/components/vacuum/triggers.yaml @@ -18,3 +18,4 @@ docked: *trigger_common errored: *trigger_common paused_cleaning: *trigger_common started_cleaning: *trigger_common +started_returning: *trigger_common diff --git a/homeassistant/components/vallox/manifest.json b/homeassistant/components/vallox/manifest.json index bbc806d8f38..9cb3c739825 100644 --- a/homeassistant/components/vallox/manifest.json +++ b/homeassistant/components/vallox/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/vallox", "iot_class": "local_polling", "loggers": ["vallox_websocket_api"], - "requirements": ["vallox-websocket-api==5.3.0"] + "requirements": ["vallox-websocket-api==6.0.0"] } diff --git a/homeassistant/components/vicare/climate.py b/homeassistant/components/vicare/climate.py index 603d82cbf7f..deb053eebc7 100644 --- a/homeassistant/components/vicare/climate.py +++ b/homeassistant/components/vicare/climate.py @@ -282,8 +282,10 @@ class ViCareClimate(ViCareEntity, ClimateEntity): self._attr_target_temperature = temp @property - def preset_mode(self): + def preset_mode(self) -> str | None: """Return the current preset mode, e.g., home, away, temp.""" + if self._current_program is None: + return None return HeatingProgram.to_ha_preset(self._current_program) def set_preset_mode(self, preset_mode: str) -> None: diff --git a/homeassistant/components/vicare/sensor.py b/homeassistant/components/vicare/sensor.py index a50f9fdc4f1..15e52f90a04 100644 --- a/homeassistant/components/vicare/sensor.py +++ b/homeassistant/components/vicare/sensor.py @@ -1204,8 +1204,8 @@ COMPRESSOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="compressor_inlet_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - value_getter=lambda api: api.getCompressorInletTemperature(), - unit_getter=lambda api: api.getCompressorInletTemperatureUnit(), + value_getter=lambda api: api.getInletTemperature(), + unit_getter=lambda api: api.getInletTemperatureUnit(), entity_registry_enabled_default=False, ), ViCareSensorEntityDescription( @@ -1213,8 +1213,8 @@ COMPRESSOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="compressor_outlet_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - value_getter=lambda api: api.getCompressorOutletTemperature(), - unit_getter=lambda api: api.getCompressorOutletTemperatureUnit(), + value_getter=lambda api: api.getOutletTemperature(), + unit_getter=lambda api: api.getOutletTemperatureUnit(), entity_registry_enabled_default=False, ), ViCareSensorEntityDescription( @@ -1222,8 +1222,8 @@ COMPRESSOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="compressor_inlet_pressure", device_class=SensorDeviceClass.PRESSURE, native_unit_of_measurement=UnitOfPressure.BAR, - value_getter=lambda api: api.getCompressorInletPressure(), - unit_getter=lambda api: api.getCompressorInletPressureUnit(), + value_getter=lambda api: api.getInletPressure(), + unit_getter=lambda api: api.getInletPressureUnit(), entity_registry_enabled_default=False, ), ViCareSensorEntityDescription( @@ -1231,8 +1231,8 @@ COMPRESSOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="compressor_outlet_pressure", device_class=SensorDeviceClass.PRESSURE, native_unit_of_measurement=UnitOfPressure.BAR, - value_getter=lambda api: api.getCompressorOutletPressure(), - unit_getter=lambda api: api.getCompressorOutletPressureUnit(), + value_getter=lambda api: api.getOutletPressure(), + unit_getter=lambda api: api.getOutletPressureUnit(), entity_registry_enabled_default=False, ), ) @@ -1243,8 +1243,8 @@ CONDENSER_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="condenser_liquid_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - value_getter=lambda api: api.getCondensorLiquidTemperature(), - unit_getter=lambda api: api.getCondensorLiquidTemperatureUnit(), + value_getter=lambda api: api.getLiquidTemperature(), + unit_getter=lambda api: api.getLiquidTemperatureUnit(), entity_registry_enabled_default=False, ), ViCareSensorEntityDescription( @@ -1252,8 +1252,8 @@ CONDENSER_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="condenser_subcooling_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - value_getter=lambda api: api.getCondensorSubcoolingTemperature(), - unit_getter=lambda api: api.getCondensorSubcoolingTemperatureUnit(), + value_getter=lambda api: api.getSubcoolingTemperature(), + unit_getter=lambda api: api.getSubcoolingTemperatureUnit(), entity_registry_enabled_default=False, ), ) @@ -1264,8 +1264,8 @@ EVAPORATOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="evaporator_overheat_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - value_getter=lambda api: api.getEvaporatorOverheatTemperature(), - unit_getter=lambda api: api.getEvaporatorOverheatTemperatureUnit(), + value_getter=lambda api: api.getOverheatTemperature(), + unit_getter=lambda api: api.getOverheatTemperatureUnit(), entity_registry_enabled_default=False, ), ViCareSensorEntityDescription( @@ -1273,8 +1273,8 @@ EVAPORATOR_SENSORS: tuple[ViCareSensorEntityDescription, ...] = ( translation_key="evaporator_liquid_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, - value_getter=lambda api: api.getEvaporatorLiquidTemperature(), - unit_getter=lambda api: api.getEvaporatorLiquidTemperatureUnit(), + value_getter=lambda api: api.getLiquidTemperature(), + unit_getter=lambda api: api.getLiquidTemperatureUnit(), entity_registry_enabled_default=False, ), ) diff --git a/homeassistant/components/vodafone_station/__init__.py b/homeassistant/components/vodafone_station/__init__.py index f070464800c..6d8bbf7b8ea 100644 --- a/homeassistant/components/vodafone_station/__init__.py +++ b/homeassistant/components/vodafone_station/__init__.py @@ -10,7 +10,12 @@ from .const import _LOGGER, CONF_DEVICE_DETAILS, DEVICE_TYPE, DEVICE_URL from .coordinator import VodafoneConfigEntry, VodafoneStationRouter from .utils import async_client_session -PLATFORMS = [Platform.BUTTON, Platform.DEVICE_TRACKER, Platform.SENSOR] +PLATFORMS = [ + Platform.BUTTON, + Platform.DEVICE_TRACKER, + Platform.IMAGE, + Platform.SENSOR, +] async def async_setup_entry(hass: HomeAssistant, entry: VodafoneConfigEntry) -> bool: diff --git a/homeassistant/components/vodafone_station/coordinator.py b/homeassistant/components/vodafone_station/coordinator.py index e03f6ebde54..6a5d8494669 100644 --- a/homeassistant/components/vodafone_station/coordinator.py +++ b/homeassistant/components/vodafone_station/coordinator.py @@ -54,6 +54,7 @@ class UpdateCoordinatorDataType: devices: dict[str, VodafoneStationDeviceInfo] sensors: dict[str, Any] + wifi: dict[str, Any] class VodafoneStationRouter(DataUpdateCoordinator[UpdateCoordinatorDataType]): @@ -137,6 +138,7 @@ class VodafoneStationRouter(DataUpdateCoordinator[UpdateCoordinatorDataType]): await self.api.login() raw_data_devices = await self.api.get_devices_data() data_sensors = await self.api.get_sensor_data() + data_wifi = await self.api.get_wifi_data() await self.api.logout() except exceptions.CannotAuthenticate as err: raise ConfigEntryAuthFailed( @@ -178,7 +180,7 @@ class VodafoneStationRouter(DataUpdateCoordinator[UpdateCoordinatorDataType]): self.previous_devices = current_devices - return UpdateCoordinatorDataType(data_devices, data_sensors) + return UpdateCoordinatorDataType(data_devices, data_sensors, data_wifi) @property def signal_device_new(self) -> str: diff --git a/homeassistant/components/vodafone_station/image.py b/homeassistant/components/vodafone_station/image.py new file mode 100644 index 00000000000..f28d7eb9955 --- /dev/null +++ b/homeassistant/components/vodafone_station/image.py @@ -0,0 +1,87 @@ +"""Vodafone Station image.""" + +from __future__ import annotations + +from io import BytesIO +from typing import Final, cast + +from aiovodafone.const import WIFI_DATA + +from homeassistant.components.image import ImageEntity, ImageEntityDescription +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import _LOGGER +from .coordinator import VodafoneConfigEntry, VodafoneStationRouter + +# Coordinator is used to centralize the data updates +PARALLEL_UPDATES = 0 + + +IMAGE_TYPES: Final = ( + ImageEntityDescription( + key="guest", + translation_key="guest", + ), + ImageEntityDescription( + key="guest_5g", + translation_key="guest_5g", + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: VodafoneConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Guest WiFi QR code for device.""" + _LOGGER.debug("Setting up Vodafone Station images") + + coordinator = entry.runtime_data + + wifi = coordinator.data.wifi + + async_add_entities( + VodafoneGuestWifiQRImage(hass, coordinator, image_desc) + for image_desc in IMAGE_TYPES + if image_desc.key in wifi[WIFI_DATA] + and "qr_code" in wifi[WIFI_DATA][image_desc.key] + ) + + +class VodafoneGuestWifiQRImage( + CoordinatorEntity[VodafoneStationRouter], + ImageEntity, +): + """Implementation of the Guest wifi QR code image entity.""" + + _attr_content_type = "image/png" + _attr_entity_category = EntityCategory.DIAGNOSTIC + _attr_has_entity_name = True + + def __init__( + self, + hass: HomeAssistant, + coordinator: VodafoneStationRouter, + description: ImageEntityDescription, + ) -> None: + """Initialize QR code image entity.""" + super().__init__(coordinator) + ImageEntity.__init__(self, hass) + + self.entity_description = description + self._attr_device_info = coordinator.device_info + self._attr_unique_id = f"{coordinator.serial_number}-{description.key}-qr-code" + + async def async_image(self) -> bytes | None: + """Return QR code image bytes.""" + qr_code = cast( + BytesIO, + self.coordinator.data.wifi[WIFI_DATA][self.entity_description.key][ + "qr_code" + ], + ) + return qr_code.getvalue() diff --git a/homeassistant/components/vodafone_station/strings.json b/homeassistant/components/vodafone_station/strings.json index 0002e01307d..bf07ce79af1 100644 --- a/homeassistant/components/vodafone_station/strings.json +++ b/homeassistant/components/vodafone_station/strings.json @@ -65,6 +65,14 @@ "name": "Internet key reconnect" } }, + "image": { + "guest": { + "name": "Guest network" + }, + "guest_5g": { + "name": "Guest 5GHz network" + } + }, "sensor": { "active_connection": { "name": "Active connection", diff --git a/homeassistant/components/voip/manifest.json b/homeassistant/components/voip/manifest.json index 8c4dd6c267c..4d6756c3419 100644 --- a/homeassistant/components/voip/manifest.json +++ b/homeassistant/components/voip/manifest.json @@ -9,5 +9,5 @@ "iot_class": "local_push", "loggers": ["voip_utils"], "quality_scale": "internal", - "requirements": ["voip-utils==0.3.4"] + "requirements": ["voip-utils==0.3.5"] } diff --git a/homeassistant/components/w800rf32/binary_sensor.py b/homeassistant/components/w800rf32/binary_sensor.py index 06e9e0dfdac..c8cc166ec01 100644 --- a/homeassistant/components/w800rf32/binary_sensor.py +++ b/homeassistant/components/w800rf32/binary_sensor.py @@ -2,6 +2,7 @@ from __future__ import annotations +from datetime import timedelta import logging import voluptuous as vol @@ -10,6 +11,7 @@ import W800rf32 as w800 from homeassistant.components.binary_sensor import ( DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA as BINARY_SENSOR_PLATFORM_SCHEMA, + BinarySensorDeviceClass, BinarySensorEntity, ) from homeassistant.const import CONF_DEVICE_CLASS, CONF_DEVICES, CONF_NAME @@ -30,7 +32,7 @@ PLATFORM_SCHEMA = BINARY_SENSOR_PLATFORM_SCHEMA.extend( vol.Required(CONF_DEVICES): { cv.string: vol.Schema( { - vol.Optional(CONF_NAME): cv.string, + vol.Required(CONF_NAME): cv.string, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, vol.Optional(CONF_OFF_DELAY): vol.All( cv.time_period, cv.positive_timedelta @@ -53,7 +55,8 @@ async def async_setup_platform( binary_sensors = [] # device_id --> "c1 or a3" X10 device. entity (type dictionary) # --> name, device_class etc - for device_id, entity in config[CONF_DEVICES].items(): + devices_config: dict[str, ConfigType] = config[CONF_DEVICES] + for device_id, entity in devices_config.items(): _LOGGER.debug( "Add %s w800rf32.binary_sensor (class %s)", entity[CONF_NAME], @@ -62,7 +65,7 @@ async def async_setup_platform( device = W800rf32BinarySensor( device_id, - entity.get(CONF_NAME), + entity[CONF_NAME], entity.get(CONF_DEVICE_CLASS), entity.get(CONF_OFF_DELAY), ) @@ -77,13 +80,21 @@ class W800rf32BinarySensor(BinarySensorEntity): _attr_should_poll = False - def __init__(self, device_id, name, device_class=None, off_delay=None): + def __init__( + self, + device_id: str, + name: str, + device_class: BinarySensorDeviceClass | None, + off_delay: timedelta | None, + ) -> None: """Initialize the w800rf32 sensor.""" self._signal = W800RF32_DEVICE.format(device_id) - self._name = name - self._device_class = device_class + + self._attr_name = name + self._attr_device_class = device_class + self._attr_is_on = False + self._off_delay = off_delay - self._state = False self._delay_listener = None @callback @@ -92,21 +103,6 @@ class W800rf32BinarySensor(BinarySensorEntity): self._delay_listener = None self.update_state(False) - @property - def name(self): - """Return the device name.""" - return self._name - - @property - def device_class(self): - """Return the sensor class.""" - return self._device_class - - @property - def is_on(self): - """Return true if the sensor state is True.""" - return self._state - @callback def binary_sensor_update(self, event): """Call for control updates from the w800rf32 gateway.""" @@ -131,9 +127,9 @@ class W800rf32BinarySensor(BinarySensorEntity): self.hass, self._off_delay, self._off_delay_listener ) - def update_state(self, state): + def update_state(self, state: bool) -> None: """Update the state of the device.""" - self._state = state + self._attr_is_on = state self.async_write_ha_state() async def async_added_to_hass(self) -> None: diff --git a/homeassistant/components/waterfurnace/manifest.json b/homeassistant/components/waterfurnace/manifest.json index be94ffd6fc5..15ac301a739 100644 --- a/homeassistant/components/waterfurnace/manifest.json +++ b/homeassistant/components/waterfurnace/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_polling", "loggers": ["waterfurnace"], "quality_scale": "legacy", - "requirements": ["waterfurnace==1.2.0"] + "requirements": ["waterfurnace==1.4.0"] } diff --git a/homeassistant/components/wirelesstag/__init__.py b/homeassistant/components/wirelesstag/__init__.py index 806e7abed00..8cc4c53a479 100644 --- a/homeassistant/components/wirelesstag/__init__.py +++ b/homeassistant/components/wirelesstag/__init__.py @@ -4,7 +4,7 @@ import logging from requests.exceptions import ConnectTimeout, HTTPError import voluptuous as vol -from wirelesstagpy import WirelessTags +from wirelesstagpy import SensorTag, WirelessTags from wirelesstagpy.exceptions import WirelessTagsException from homeassistant.components import persistent_notification @@ -14,7 +14,12 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.dispatcher import dispatcher_send from homeassistant.helpers.typing import ConfigType -from .const import DOMAIN, SIGNAL_BINARY_EVENT_UPDATE, SIGNAL_TAG_UPDATE +from .const import ( + DOMAIN, + SIGNAL_BINARY_EVENT_UPDATE, + SIGNAL_TAG_UPDATE, + WIRELESSTAG_DATA, +) _LOGGER = logging.getLogger(__name__) @@ -39,14 +44,14 @@ CONFIG_SCHEMA = vol.Schema( class WirelessTagPlatform: """Principal object to manage all registered in HA tags.""" - def __init__(self, hass, api): + def __init__(self, hass: HomeAssistant, api: WirelessTags) -> None: """Designated initializer for wirelesstags platform.""" self.hass = hass self.api = api - self.tags = {} + self.tags: dict[str, SensorTag] = {} self._local_base_url = None - def load_tags(self): + def load_tags(self) -> dict[str, SensorTag]: """Load tags from remote server.""" self.tags = self.api.load_tags() return self.tags @@ -104,9 +109,9 @@ class WirelessTagPlatform: def setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the Wireless Sensor Tag component.""" - conf = config[DOMAIN] - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) + conf: ConfigType = config[DOMAIN] + username: str = conf[CONF_USERNAME] + password: str = conf[CONF_PASSWORD] try: wirelesstags = WirelessTags(username=username, password=password) @@ -114,7 +119,7 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: platform = WirelessTagPlatform(hass, wirelesstags) platform.load_tags() platform.start_monitoring() - hass.data[DOMAIN] = platform + hass.data[WIRELESSTAG_DATA] = platform except (ConnectTimeout, HTTPError, WirelessTagsException) as ex: _LOGGER.error("Unable to connect to wirelesstag.net service: %s", str(ex)) persistent_notification.create( diff --git a/homeassistant/components/wirelesstag/binary_sensor.py b/homeassistant/components/wirelesstag/binary_sensor.py index 8a0957e16e3..430c4c07bde 100644 --- a/homeassistant/components/wirelesstag/binary_sensor.py +++ b/homeassistant/components/wirelesstag/binary_sensor.py @@ -3,9 +3,11 @@ from __future__ import annotations import voluptuous as vol +from wirelesstagpy import SensorTag, constants as WT_CONSTANTS from homeassistant.components.binary_sensor import ( PLATFORM_SCHEMA as BINARY_SENSOR_PLATFORM_SCHEMA, + BinarySensorDeviceClass, BinarySensorEntity, ) from homeassistant.const import CONF_MONITORED_CONDITIONS, STATE_OFF, STATE_ON, Platform @@ -15,53 +17,24 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from .const import DOMAIN, SIGNAL_BINARY_EVENT_UPDATE +from . import WirelessTagPlatform +from .const import SIGNAL_BINARY_EVENT_UPDATE, WIRELESSTAG_DATA from .entity import WirelessTagBaseSensor from .util import async_migrate_unique_id -# On means in range, Off means out of range -SENSOR_PRESENCE = "presence" - -# On means motion detected, Off means clear -SENSOR_MOTION = "motion" - -# On means open, Off means closed -SENSOR_DOOR = "door" - -# On means temperature become too cold, Off means normal -SENSOR_COLD = "cold" - -# On means hot, Off means normal -SENSOR_HEAT = "heat" - -# On means too dry (humidity), Off means normal -SENSOR_DRY = "dry" - -# On means too wet (humidity), Off means normal -SENSOR_WET = "wet" - -# On means light detected, Off means no light -SENSOR_LIGHT = "light" - -# On means moisture detected (wet), Off means no moisture (dry) -SENSOR_MOISTURE = "moisture" - -# On means tag battery is low, Off means normal -SENSOR_BATTERY = "battery" - # Sensor types: Name, device_class, push notification type representing 'on', # attr to check SENSOR_TYPES = { - SENSOR_PRESENCE: "Presence", - SENSOR_MOTION: "Motion", - SENSOR_DOOR: "Door", - SENSOR_COLD: "Cold", - SENSOR_HEAT: "Heat", - SENSOR_DRY: "Too dry", - SENSOR_WET: "Too wet", - SENSOR_LIGHT: "Light", - SENSOR_MOISTURE: "Leak", - SENSOR_BATTERY: "Low Battery", + WT_CONSTANTS.EVENT_PRESENCE: BinarySensorDeviceClass.PRESENCE, + WT_CONSTANTS.EVENT_MOTION: BinarySensorDeviceClass.MOTION, + WT_CONSTANTS.EVENT_DOOR: BinarySensorDeviceClass.DOOR, + WT_CONSTANTS.EVENT_COLD: BinarySensorDeviceClass.COLD, + WT_CONSTANTS.EVENT_HEAT: BinarySensorDeviceClass.HEAT, + WT_CONSTANTS.EVENT_DRY: None, + WT_CONSTANTS.EVENT_WET: None, + WT_CONSTANTS.EVENT_LIGHT: BinarySensorDeviceClass.LIGHT, + WT_CONSTANTS.EVENT_MOISTURE: BinarySensorDeviceClass.MOISTURE, + WT_CONSTANTS.EVENT_BATTERY: BinarySensorDeviceClass.BATTERY, } @@ -81,7 +54,7 @@ async def async_setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the platform for a WirelessTags.""" - platform = hass.data[DOMAIN] + platform = hass.data[WIRELESSTAG_DATA] sensors = [] tags = platform.tags @@ -98,11 +71,14 @@ async def async_setup_platform( class WirelessTagBinarySensor(WirelessTagBaseSensor, BinarySensorEntity): """A binary sensor implementation for WirelessTags.""" - def __init__(self, api, tag, sensor_type): + def __init__( + self, api: WirelessTagPlatform, tag: SensorTag, sensor_type: str + ) -> None: """Initialize a binary sensor for a Wireless Sensor Tags.""" super().__init__(api, tag) self._sensor_type = sensor_type self._name = f"{self._tag.name} {self.event.human_readable_name}" + self._attr_device_class = SENSOR_TYPES[sensor_type] self._attr_unique_id = f"{self._uuid}_{self._sensor_type}" async def async_added_to_hass(self) -> None: @@ -123,11 +99,6 @@ class WirelessTagBinarySensor(WirelessTagBaseSensor, BinarySensorEntity): """Return True if the binary sensor is on.""" return self._state == STATE_ON - @property - def device_class(self): - """Return the class of the binary sensor.""" - return self._sensor_type - @property def event(self): """Binary event of tag.""" diff --git a/homeassistant/components/wirelesstag/const.py b/homeassistant/components/wirelesstag/const.py index c1384606bf1..b9ddf816fb8 100644 --- a/homeassistant/components/wirelesstag/const.py +++ b/homeassistant/components/wirelesstag/const.py @@ -1,6 +1,16 @@ """Support for Wireless Sensor Tags.""" +from __future__ import annotations + +from typing import TYPE_CHECKING + +from homeassistant.util.hass_dict import HassKey + +if TYPE_CHECKING: + from . import WirelessTagPlatform + DOMAIN = "wirelesstag" +WIRELESSTAG_DATA: HassKey[WirelessTagPlatform] = HassKey(DOMAIN) # Template for signal - first parameter is tag_id, # second, tag manager mac address diff --git a/homeassistant/components/wirelesstag/sensor.py b/homeassistant/components/wirelesstag/sensor.py index 9b92480ecf9..913e1dbf7a0 100644 --- a/homeassistant/components/wirelesstag/sensor.py +++ b/homeassistant/components/wirelesstag/sensor.py @@ -20,7 +20,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from .const import DOMAIN, SIGNAL_TAG_UPDATE +from .const import DOMAIN, SIGNAL_TAG_UPDATE, WIRELESSTAG_DATA from .entity import WirelessTagBaseSensor from .util import async_migrate_unique_id @@ -78,7 +78,7 @@ async def async_setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the sensor platform.""" - platform = hass.data[DOMAIN] + platform = hass.data[WIRELESSTAG_DATA] sensors = [] tags = platform.tags for tag in tags.values(): diff --git a/homeassistant/components/wirelesstag/switch.py b/homeassistant/components/wirelesstag/switch.py index 9fa630d4f55..53e28f9103d 100644 --- a/homeassistant/components/wirelesstag/switch.py +++ b/homeassistant/components/wirelesstag/switch.py @@ -17,7 +17,7 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from .const import DOMAIN +from .const import WIRELESSTAG_DATA from .entity import WirelessTagBaseSensor from .util import async_migrate_unique_id @@ -62,7 +62,7 @@ async def async_setup_platform( discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up switches for a Wireless Sensor Tags.""" - platform = hass.data[DOMAIN] + platform = hass.data[WIRELESSTAG_DATA] tags = platform.load_tags() monitored_conditions = config[CONF_MONITORED_CONDITIONS] diff --git a/homeassistant/components/withings/strings.json b/homeassistant/components/withings/strings.json index fdb141dea81..62fc14e9a5f 100644 --- a/homeassistant/components/withings/strings.json +++ b/homeassistant/components/withings/strings.json @@ -21,6 +21,9 @@ "error": { "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "oauth_discovery": { "description": "Home Assistant has found a Withings device on your network. Be aware that the setup of Withings is more complicated than many other integrations. Press **Submit** to continue setting up Withings." diff --git a/homeassistant/components/wiz/light.py b/homeassistant/components/wiz/light.py index 509d40d654d..8a6de65cf73 100644 --- a/homeassistant/components/wiz/light.py +++ b/homeassistant/components/wiz/light.py @@ -80,6 +80,9 @@ class WizBulbEntity(WizToggleEntity, LightEntity): color_modes.add(RGB_WHITE_CHANNELS_COLOR_MODE[bulb_type.white_channels]) if features.color_tmp: color_modes.add(ColorMode.COLOR_TEMP) + kelvin = bulb_type.kelvin_range + self._attr_max_color_temp_kelvin = kelvin.max + self._attr_min_color_temp_kelvin = kelvin.min if features.brightness: color_modes.add(ColorMode.BRIGHTNESS) self._attr_supported_color_modes = filter_supported_color_modes(color_modes) @@ -87,10 +90,6 @@ class WizBulbEntity(WizToggleEntity, LightEntity): # If the light supports only a single color mode, set it now self._attr_color_mode = next(iter(self._attr_supported_color_modes)) self._attr_effect_list = wiz_data.scenes - if bulb_type.bulb_type != BulbClass.DW: - kelvin = bulb_type.kelvin_range - self._attr_max_color_temp_kelvin = kelvin.max - self._attr_min_color_temp_kelvin = kelvin.min if bulb_type.features.effect: self._attr_supported_features = LightEntityFeature.EFFECT self._async_update_attrs() diff --git a/homeassistant/components/wsdot/manifest.json b/homeassistant/components/wsdot/manifest.json index 817441a06c6..4b86d38b76f 100644 --- a/homeassistant/components/wsdot/manifest.json +++ b/homeassistant/components/wsdot/manifest.json @@ -7,6 +7,5 @@ "integration_type": "service", "iot_class": "cloud_polling", "loggers": ["wsdot"], - "quality_scale": "legacy", "requirements": ["wsdot==0.0.1"] } diff --git a/homeassistant/components/wyoming/tts.py b/homeassistant/components/wyoming/tts.py index cf088c04d9f..254d9c60429 100644 --- a/homeassistant/components/wyoming/tts.py +++ b/homeassistant/components/wyoming/tts.py @@ -47,6 +47,9 @@ async def async_setup_entry( class WyomingTtsProvider(tts.TextToSpeechEntity): """Wyoming text-to-speech provider.""" + _attr_default_options = {} + _attr_supported_options = [tts.ATTR_AUDIO_OUTPUT, tts.ATTR_VOICE, ATTR_SPEAKER] + def __init__( self, config_entry: ConfigEntry, @@ -78,38 +81,13 @@ class WyomingTtsProvider(tts.TextToSpeechEntity): self._voices[language], key=lambda v: v.name ) - self._supported_languages: list[str] = list(voice_languages) + self._attr_supported_languages = list(voice_languages) + if self._attr_supported_languages: + self._attr_default_language = self._attr_supported_languages[0] self._attr_name = self._tts_service.name self._attr_unique_id = f"{config_entry.entry_id}-tts" - @property - def default_language(self): - """Return default language.""" - if not self._supported_languages: - return None - - return self._supported_languages[0] - - @property - def supported_languages(self): - """Return list of supported languages.""" - return self._supported_languages - - @property - def supported_options(self): - """Return list of supported options like voice, emotion.""" - return [ - tts.ATTR_AUDIO_OUTPUT, - tts.ATTR_VOICE, - ATTR_SPEAKER, - ] - - @property - def default_options(self): - """Return a dict include default options.""" - return {} - @callback def async_get_supported_voices(self, language: str) -> list[tts.Voice] | None: """Return a list of supported voices for a language.""" diff --git a/homeassistant/components/xbox/media_player.py b/homeassistant/components/xbox/media_player.py index 36cb73aff54..66379303bc7 100644 --- a/homeassistant/components/xbox/media_player.py +++ b/homeassistant/components/xbox/media_player.py @@ -157,6 +157,8 @@ class XboxMediaPlayer(XboxConsoleBaseEntity, MediaPlayerEntity): await self.client.smartglass.mute(self._console.id) else: await self.client.smartglass.unmute(self._console.id) + self._attr_is_volume_muted = mute + self.async_write_ha_state() async def async_volume_up(self) -> None: """Turn volume up for media player.""" diff --git a/homeassistant/components/xbox/strings.json b/homeassistant/components/xbox/strings.json index 193b7bdfa53..acd9021b069 100644 --- a/homeassistant/components/xbox/strings.json +++ b/homeassistant/components/xbox/strings.json @@ -15,6 +15,9 @@ "create_entry": { "default": "[%key:common::config_flow::create_entry::authenticated%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "oauth_discovery": { "description": "Home Assistant has found an Xbox device on your network. Press **Submit** to continue setting up the Xbox integration.", diff --git a/homeassistant/components/xiaomi_ble/manifest.json b/homeassistant/components/xiaomi_ble/manifest.json index 513c2c72994..c81374741a2 100644 --- a/homeassistant/components/xiaomi_ble/manifest.json +++ b/homeassistant/components/xiaomi_ble/manifest.json @@ -25,5 +25,5 @@ "documentation": "https://www.home-assistant.io/integrations/xiaomi_ble", "integration_type": "device", "iot_class": "local_push", - "requirements": ["xiaomi-ble==1.4.1"] + "requirements": ["xiaomi-ble==1.5.0"] } diff --git a/homeassistant/components/xmpp/notify.py b/homeassistant/components/xmpp/notify.py index d44a826e50c..964f66f1db2 100644 --- a/homeassistant/components/xmpp/notify.py +++ b/homeassistant/components/xmpp/notify.py @@ -9,6 +9,7 @@ import mimetypes import pathlib import random import string +from typing import Any import requests import slixmpp @@ -101,7 +102,7 @@ class XmppNotificationService(BaseNotificationService): self._verify = verify self._room = room - async def async_send_message(self, message="", **kwargs): + async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a user.""" title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) text = f"{title}: {message}" if title else message diff --git a/homeassistant/components/yolink/sensor.py b/homeassistant/components/yolink/sensor.py index cf7cd2a16d9..d6f0c620c7f 100644 --- a/homeassistant/components/yolink/sensor.py +++ b/homeassistant/components/yolink/sensor.py @@ -212,6 +212,7 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = ( key="battery", device_class=SensorDeviceClass.BATTERY, native_unit_of_measurement=PERCENTAGE, + entity_category=EntityCategory.DIAGNOSTIC, state_class=SensorStateClass.MEASUREMENT, exists_fn=lambda device: device.device_type in BATTERY_POWER_SENSOR, should_update_entity=lambda value: value is not None, @@ -251,9 +252,11 @@ SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = ( # mcu temperature YoLinkSensorEntityDescription( key="devTemperature", + translation_key="device_temperature", device_class=SensorDeviceClass.TEMPERATURE, native_unit_of_measurement=UnitOfTemperature.CELSIUS, state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, exists_fn=lambda device: device.device_type in MCU_DEV_TEMPERATURE_SENSOR, should_update_entity=lambda value: value is not None, value=lambda device, data: data.get("devTemperature"), diff --git a/homeassistant/components/yolink/strings.json b/homeassistant/components/yolink/strings.json index ee6d6c23c41..449a5a7028b 100644 --- a/homeassistant/components/yolink/strings.json +++ b/homeassistant/components/yolink/strings.json @@ -67,6 +67,9 @@ "current_power": { "name": "Current power" }, + "device_temperature": { + "name": "Device temperature" + }, "power_consumption": { "name": "Power consumption" }, diff --git a/homeassistant/components/youtube/strings.json b/homeassistant/components/youtube/strings.json index 2672f249de8..18d90974cd3 100644 --- a/homeassistant/components/youtube/strings.json +++ b/homeassistant/components/youtube/strings.json @@ -17,6 +17,9 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]" }, + "initiate_flow": { + "user": "[%key:common::config_flow::initiate_flow::account%]" + }, "step": { "channels": { "data": { "channels": "YouTube channels" }, diff --git a/homeassistant/components/zwave_js/__init__.py b/homeassistant/components/zwave_js/__init__.py index 2076c37856e..e14fd0757f6 100644 --- a/homeassistant/components/zwave_js/__init__.py +++ b/homeassistant/components/zwave_js/__init__.py @@ -840,19 +840,26 @@ class NodeEvents: # After ensuring the node is set up in HA, we should check if the node's # device config has changed, and if so, issue a repair registry entry for a # possible reinterview - if not node.is_controller_node and await node.async_has_device_config_changed(): - device_name = device.name_by_user or device.name or "Unnamed device" - async_create_issue( - self.hass, - DOMAIN, - f"device_config_file_changed.{device.id}", - data={"device_id": device.id, "device_name": device_name}, - is_fixable=True, - is_persistent=False, - translation_key="device_config_file_changed", - translation_placeholders={"device_name": device_name}, - severity=IssueSeverity.WARNING, - ) + if not node.is_controller_node: + issue_id = f"device_config_file_changed.{device.id}" + if await node.async_has_device_config_changed(): + device_name = device.name_by_user or device.name or "Unnamed device" + async_create_issue( + self.hass, + DOMAIN, + issue_id, + data={"device_id": device.id, "device_name": device_name}, + is_fixable=True, + is_persistent=False, + translation_key="device_config_file_changed", + translation_placeholders={"device_name": device_name}, + severity=IssueSeverity.WARNING, + ) + else: + # Clear any existing repair issue if the device config is not considered + # changed. This can happen when the original issue was created by + # an upstream bug, or the change has been reverted. + async_delete_issue(self.hass, DOMAIN, issue_id) async def async_handle_discovery_info( self, diff --git a/homeassistant/components/zwave_js/manifest.json b/homeassistant/components/zwave_js/manifest.json index 1b28da3ab9d..cdef87d987a 100644 --- a/homeassistant/components/zwave_js/manifest.json +++ b/homeassistant/components/zwave_js/manifest.json @@ -9,7 +9,7 @@ "integration_type": "hub", "iot_class": "local_push", "loggers": ["zwave_js_server"], - "requirements": ["pyserial==3.5", "zwave-js-server-python==0.67.1"], + "requirements": ["pyserial==3.5", "zwave-js-server-python==0.68.0"], "usb": [ { "known_devices": ["Aeotec Z-Stick Gen5+", "Z-WaveMe UZB"], diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index beb86c1fd46..5df715b03ca 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -5,15 +5,14 @@ from __future__ import annotations import abc import asyncio from collections import defaultdict -from collections.abc import Callable, Container, Coroutine, Hashable, Iterable, Mapping +from collections.abc import Callable, Container, Hashable, Iterable, Mapping from contextlib import suppress import copy from dataclasses import dataclass from enum import StrEnum -import functools import logging from types import MappingProxyType -from typing import Any, Concatenate, Generic, Required, TypedDict, TypeVar, cast +from typing import Any, Generic, Required, TypedDict, TypeVar, cast import voluptuous as vol @@ -151,15 +150,6 @@ class FlowResult(TypedDict, Generic[_FlowContextT, _HandlerT], total=False): url: str -class ProgressStepData[_FlowResultT](TypedDict): - """Typed data for progress step tracking.""" - - tasks: dict[str, asyncio.Task[Any]] - abort_reason: str - abort_description_placeholders: Mapping[str, str] - next_step_result: _FlowResultT | None - - def _map_error_to_schema_errors( schema_errors: dict[str, Any], error: vol.Invalid, @@ -645,24 +635,6 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]): __progress_task: asyncio.Task[Any] | None = None __no_progress_task_reported = False deprecated_show_progress = False - __progress_step_data: ProgressStepData[_FlowResultT] | None = None - - @property - def _progress_step_data(self) -> ProgressStepData[_FlowResultT]: - """Return progress step data. - - A property is used instead of a simple attribute as derived classes - do not call super().__init__. - The property makes sure that the dict is initialized if needed. - """ - if not self.__progress_step_data: - self.__progress_step_data = { - "tasks": {}, - "abort_reason": "", - "abort_description_placeholders": MappingProxyType({}), - "next_step_result": None, - } - return self.__progress_step_data @property def source(self) -> str | None: @@ -785,39 +757,6 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]): description_placeholders=description_placeholders, ) - async def async_step__progress_step_abort( - self, user_input: dict[str, Any] | None = None - ) -> _FlowResultT: - """Abort the flow.""" - progress_step_data = self._progress_step_data - return self.async_abort( - reason=progress_step_data["abort_reason"], - description_placeholders=progress_step_data[ - "abort_description_placeholders" - ], - ) - - async def async_step__progress_step_progress_done( - self, user_input: dict[str, Any] | None = None - ) -> _FlowResultT: - """Progress done. Return the next step. - - Used by the progress_step decorator - to allow decorated step methods - to call the next step method, to change step, - without using async_show_progress_done. - If no next step is set, abort the flow. - """ - progress_step_data = self._progress_step_data - if (next_step_result := progress_step_data["next_step_result"]) is None: - return self.async_abort( - reason=progress_step_data["abort_reason"], - description_placeholders=progress_step_data[ - "abort_description_placeholders" - ], - ) - return next_step_result - @callback def async_external_step( self, @@ -998,90 +937,3 @@ class section: def __call__(self, value: Any) -> Any: """Validate input.""" return self.schema(value) - - -type _FuncType[_T: FlowHandler[Any, Any, Any], _R: FlowResult[Any, Any], **_P] = ( - Callable[Concatenate[_T, _P], Coroutine[Any, Any, _R]] -) - - -def progress_step[ - HandlerT: FlowHandler[Any, Any, Any], - ResultT: FlowResult[Any, Any], - **P, -]( - description_placeholders: ( - dict[str, str] | Callable[[Any], dict[str, str]] | None - ) = None, -) -> Callable[[_FuncType[HandlerT, ResultT, P]], _FuncType[HandlerT, ResultT, P]]: - """Decorator to create a progress step from an async function. - - The decorated method should be a step method - which needs to show progress. - The method should accept dict[str, Any] as user_input - and should return a FlowResult or raise AbortFlow. - The method can call self.async_update_progress(progress) - to update progress. - - Args: - description_placeholders: Static dict or callable that returns dict for progress UI placeholders. - """ - - def decorator( - func: _FuncType[HandlerT, ResultT, P], - ) -> _FuncType[HandlerT, ResultT, P]: - @functools.wraps(func) - async def wrapper( - self: FlowHandler[Any, ResultT], *args: P.args, **kwargs: P.kwargs - ) -> ResultT: - step_id = func.__name__.replace("async_step_", "") - progress_step_data = self._progress_step_data - # Check if we have a progress task running - progress_task = progress_step_data["tasks"].get(step_id) - - if progress_task is None: - # First call - create and start the progress task - progress_task = self.hass.async_create_task( - func(self, *args, **kwargs), # type: ignore[arg-type] - f"Progress step {step_id}", - ) - progress_step_data["tasks"][step_id] = progress_task - - if not progress_task.done(): - # Handle description placeholders - placeholders = None - if description_placeholders is not None: - if callable(description_placeholders): - placeholders = description_placeholders(self) - else: - placeholders = description_placeholders - - return self.async_show_progress( - step_id=step_id, - progress_action=step_id, - progress_task=progress_task, - description_placeholders=placeholders, - ) - - # Task is done or this is a subsequent call - try: - progress_step_data["next_step_result"] = await progress_task - except AbortFlow as err: - progress_step_data["abort_reason"] = err.reason - progress_step_data["abort_description_placeholders"] = ( - err.description_placeholders or {} - ) - return self.async_show_progress_done( - next_step_id="_progress_step_abort" - ) - finally: - # Clean up task reference - progress_step_data["tasks"].pop(step_id, None) - - return self.async_show_progress_done( - next_step_id="_progress_step_progress_done" - ) - - return wrapper - - return decorator diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py index 2f0829b0756..83f00f52d54 100644 --- a/homeassistant/generated/config_flows.py +++ b/homeassistant/generated/config_flows.py @@ -443,6 +443,7 @@ FLOWS = { "mystrom", "myuplink", "nam", + "namecheapdns", "nanoleaf", "nasweb", "neato", @@ -536,6 +537,7 @@ FLOWS = { "prosegur", "prowl", "proximity", + "proxmoxve", "prusalink", "ps4", "pterodactyl", diff --git a/homeassistant/generated/integrations.json b/homeassistant/generated/integrations.json index 9ad1ad0e827..5319c300eea 100644 --- a/homeassistant/generated/integrations.json +++ b/homeassistant/generated/integrations.json @@ -4343,8 +4343,8 @@ }, "namecheapdns": { "name": "Namecheap DynamicDNS", - "integration_type": "hub", - "config_flow": false, + "integration_type": "service", + "config_flow": true, "iot_class": "cloud_push" }, "nanoleaf": { @@ -5245,8 +5245,8 @@ }, "proxmoxve": { "name": "Proxmox VE", - "integration_type": "hub", - "config_flow": false, + "integration_type": "service", + "config_flow": true, "iot_class": "local_polling" }, "proxy": { @@ -5375,7 +5375,7 @@ "name": "QNAP" }, "qnap_qsw": { - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_polling", "name": "QNAP QSW" @@ -5413,7 +5413,7 @@ }, "rabbitair": { "name": "Rabbit Air", - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_polling" }, @@ -5438,7 +5438,7 @@ }, "radiotherm": { "name": "Radio Thermostat", - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_polling" }, @@ -5473,7 +5473,7 @@ }, "rapt_ble": { "name": "RAPT Bluetooth", - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_push" }, @@ -5571,7 +5571,7 @@ }, "renson": { "name": "Renson", - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_polling" }, @@ -5679,13 +5679,13 @@ }, "romy": { "name": "ROMY Vacuum Cleaner", - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_polling" }, "roomba": { "name": "iRobot Roomba and Braava", - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_push" }, @@ -5720,7 +5720,7 @@ }, "rova": { "name": "ROVA", - "integration_type": "hub", + "integration_type": "service", "config_flow": true, "iot_class": "cloud_polling" }, @@ -5763,13 +5763,13 @@ "name": "Ruuvi", "integrations": { "ruuvi_gateway": { - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_polling", "name": "Ruuvi Gateway" }, "ruuvitag_ble": { - "integration_type": "hub", + "integration_type": "device", "config_flow": true, "iot_class": "local_push", "name": "Ruuvi BLE" @@ -5784,7 +5784,7 @@ }, "sabnzbd": { "name": "SABnzbd", - "integration_type": "hub", + "integration_type": "service", "config_flow": true, "iot_class": "local_polling" }, diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index 957ff25434f..2c82756c0a4 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -13,7 +13,18 @@ import inspect import logging import re import sys -from typing import TYPE_CHECKING, Any, Protocol, TypedDict, Unpack, cast, overload +from typing import ( + TYPE_CHECKING, + Any, + Final, + Literal, + Protocol, + TypedDict, + Unpack, + cast, + overload, + override, +) import voluptuous as vol @@ -43,7 +54,7 @@ from homeassistant.const import ( STATE_UNKNOWN, WEEKDAYS, ) -from homeassistant.core import HomeAssistant, State, callback +from homeassistant.core import HomeAssistant, State, callback, split_entity_id from homeassistant.exceptions import ( ConditionError, ConditionErrorContainer, @@ -71,6 +82,7 @@ from .automation import ( ) from .integration_platform import async_process_integration_platforms from .selector import TargetSelector +from .target import TargetSelection, async_extract_referenced_entity_ids from .template import Template, render_complex from .trace import ( TraceElement, @@ -302,6 +314,112 @@ class Condition(abc.ABC): """Get the condition checker.""" +ATTR_BEHAVIOR: Final = "behavior" +BEHAVIOR_ANY: Final = "any" +BEHAVIOR_ALL: Final = "all" + +STATE_CONDITION_OPTIONS_SCHEMA: dict[vol.Marker, Any] = { + vol.Required(ATTR_BEHAVIOR, default=BEHAVIOR_ANY): vol.In( + [BEHAVIOR_ANY, BEHAVIOR_ALL] + ), +} +ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL = vol.Schema( + { + vol.Required(CONF_TARGET): cv.TARGET_FIELDS, + vol.Required(CONF_OPTIONS): STATE_CONDITION_OPTIONS_SCHEMA, + } +) + + +class EntityStateConditionBase(Condition): + """State condition.""" + + _domain: str + _schema: vol.Schema = ENTITY_STATE_CONDITION_SCHEMA_ANY_ALL + _states: set[str] + + @override + @classmethod + async def async_validate_config( + cls, hass: HomeAssistant, config: ConfigType + ) -> ConfigType: + """Validate config.""" + return cast(ConfigType, cls._schema(config)) + + def __init__(self, hass: HomeAssistant, config: ConditionConfig) -> None: + """Initialize condition.""" + super().__init__(hass, config) + if TYPE_CHECKING: + assert config.target + assert config.options + self._target_selection = TargetSelection(config.target) + self._behavior = config.options[ATTR_BEHAVIOR] + + def entity_filter(self, entities: set[str]) -> set[str]: + """Filter entities of this domain.""" + return { + entity_id + for entity_id in entities + if split_entity_id(entity_id)[0] == self._domain + } + + @override + async def async_get_checker(self) -> ConditionChecker: + """Get the condition checker.""" + + def check_any_match_state(states: list[str]) -> bool: + """Test if any entity match the state.""" + return any(state in self._states for state in states) + + def check_all_match_state(states: list[str]) -> bool: + """Test if all entities match the state.""" + return all(state in self._states for state in states) + + matcher: Callable[[list[str]], bool] + if self._behavior == BEHAVIOR_ANY: + matcher = check_any_match_state + elif self._behavior == BEHAVIOR_ALL: + matcher = check_all_match_state + + def test_state(**kwargs: Unpack[ConditionCheckParams]) -> bool: + """Test state condition.""" + targeted_entities = async_extract_referenced_entity_ids( + self._hass, self._target_selection, expand_group=False + ) + referenced_entity_ids = targeted_entities.referenced.union( + targeted_entities.indirectly_referenced + ) + filtered_entity_ids = self.entity_filter(referenced_entity_ids) + entity_states = [ + _state.state + for entity_id in filtered_entity_ids + if (_state := self._hass.states.get(entity_id)) + and _state.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN) + ] + return matcher(entity_states) + + return test_state + + +def make_entity_state_condition( + domain: str, states: str | set[str] +) -> type[EntityStateConditionBase]: + """Create a condition for entity state changes to specific state(s).""" + + if isinstance(states, str): + states_set = {states} + else: + states_set = states + + class CustomCondition(EntityStateConditionBase): + """Condition for entity state.""" + + _domain = domain + _states = states_set + + return CustomCondition + + class ConditionProtocol(Protocol): """Define the format of condition modules.""" @@ -1229,13 +1347,18 @@ def async_extract_entities(config: ConfigType | Template) -> set[str]: if entity_ids is not None: referenced.update(entity_ids) + if target_entities := _get_targets_from_condition_config( + config, CONF_ENTITY_ID + ): + referenced.update(target_entities) + return referenced @callback def async_extract_devices(config: ConfigType | Template) -> set[str]: """Extract devices from a condition.""" - referenced = set() + referenced: set[str] = set() to_process = deque([config]) while to_process: @@ -1249,15 +1372,57 @@ def async_extract_devices(config: ConfigType | Template) -> set[str]: to_process.extend(config["conditions"]) continue - if condition != "device": + if condition == "device": + if (device_id := config.get(CONF_DEVICE_ID)) is not None: + referenced.add(device_id) continue - if (device_id := config.get(CONF_DEVICE_ID)) is not None: - referenced.add(device_id) + if target_devices := _get_targets_from_condition_config(config, CONF_DEVICE_ID): + referenced.update(target_devices) return referenced +@callback +def async_extract_targets( + config: ConfigType | Template, + target_type: Literal["area_id", "floor_id", "label_id"], +) -> set[str]: + """Extract targets from a condition.""" + referenced: set[str] = set() + to_process = deque([config]) + + while to_process: + config = to_process.popleft() + if isinstance(config, Template): + continue + + condition = config[CONF_CONDITION] + + if condition in ("and", "not", "or"): + to_process.extend(config["conditions"]) + continue + + if targets := _get_targets_from_condition_config(config, target_type): + referenced.update(targets) + + return referenced + + +@callback +def _get_targets_from_condition_config( + config: ConfigType, + target: Literal["entity_id", "device_id", "area_id", "floor_id", "label_id"], +) -> list[str]: + """Extract targets from a condition target config.""" + if not (target_conf := config.get(CONF_TARGET)): + return [] + if not (targets := target_conf.get(target)): + return [] + + return [targets] if isinstance(targets, str) else targets + + def _load_conditions_file(integration: Integration) -> dict[str, Any]: """Load conditions file for an integration.""" try: diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 9a52a8edace..94aa8b626d8 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -452,6 +452,11 @@ class Entity( # Entity description instance for this Entity entity_description: EntityDescription + # Integration suggested object id, derived from entity_id, if it is set by the + # integration before the entity is added. + # Only handled internally, never to be used by integrations. + internal_integration_suggested_object_id: str | None + # If we reported if this entity was slow _slow_reported = False @@ -715,7 +720,7 @@ class Entity( @property def suggested_object_id(self) -> str | None: - """Return input for object id.""" + """Return suggested object id.""" if ( # Check our class has overridden the name property from Entity # We need to use type.__getattribute__ to retrieve the underlying @@ -733,6 +738,7 @@ class Entity( ) else: name = self.name + return None if name is UNDEFINED else name @cached_property diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 7fbeaad28f4..cf13e27c2cf 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -29,8 +29,8 @@ from homeassistant.loader import async_get_integration, bind_hass from homeassistant.setup import async_prepare_setup_platform from homeassistant.util.hass_dict import HassKey -from . import device_registry as dr, discovery, entity, entity_registry as er, service -from .entity_platform import EntityPlatform, async_calculate_suggested_object_id +from . import discovery, entity, service +from .entity_platform import EntityPlatform from .typing import ConfigType, DiscoveryInfoType, VolDictType, VolSchemaType DEFAULT_SCAN_INTERVAL = timedelta(seconds=15) @@ -58,36 +58,6 @@ async def async_update_entity(hass: HomeAssistant, entity_id: str) -> None: await entity_obj.async_update_ha_state(True) -@callback -def async_get_entity_suggested_object_id( - hass: HomeAssistant, entity_id: str -) -> str | None: - """Get the suggested object id for an entity. - - Raises HomeAssistantError if the entity is not in the registry or - is not backed by an object. - """ - entity_registry = er.async_get(hass) - if not (entity_entry := entity_registry.async_get(entity_id)): - raise HomeAssistantError(f"Entity {entity_id} is not in the registry.") - - domain = entity_id.partition(".")[0] - - if entity_entry.name: - return entity_entry.name - - if entity_entry.suggested_object_id: - return entity_entry.suggested_object_id - - entity_comp = hass.data.get(DATA_INSTANCES, {}).get(domain) - if not (entity_obj := entity_comp.get_entity(entity_id) if entity_comp else None): - raise HomeAssistantError(f"Entity {entity_id} has no object.") - device: dr.DeviceEntry | None = None - if device_id := entity_entry.device_id: - device = dr.async_get(hass).async_get(device_id) - return async_calculate_suggested_object_id(entity_obj, device) - - class EntityComponent[_EntityT: entity.Entity = entity.Entity]: """The EntityComponent manages platforms that manage entities. diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index 514f0dcae5d..a57345023c9 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -7,7 +7,7 @@ from collections.abc import Awaitable, Callable, Coroutine, Iterable, Mapping from contextvars import ContextVar from datetime import timedelta from logging import Logger, getLogger -from typing import TYPE_CHECKING, Any, Protocol +from typing import TYPE_CHECKING, Any, Protocol, overload from homeassistant import config_entries from homeassistant.const import ( @@ -38,12 +38,7 @@ from homeassistant.setup import SetupPhases, async_start_setup from homeassistant.util.async_ import create_eager_task from homeassistant.util.hass_dict import HassKey -from . import ( - device_registry as dev_reg, - entity_registry as ent_reg, - service, - translation, -) +from . import device_registry as dr, entity_registry as er, service, translation from .deprecation import deprecated_function from .entity_registry import EntityRegistry, RegistryEntryDisabler, RegistryEntryHider from .event import async_call_later @@ -624,7 +619,7 @@ class EntityPlatform: event loop and will finish faster if we run them concurrently. """ results: list[BaseException | None] | None = None - entity_registry = ent_reg.async_get(self.hass) + entity_registry = er.async_get(self.hass) try: async with self.hass.timeout.async_timeout(timeout, self.domain): results = await asyncio.gather( @@ -676,7 +671,7 @@ class EntityPlatform: to the event loop so we can await the coros directly without scheduling them as tasks. """ - entity_registry = ent_reg.async_get(self.hass) + entity_registry = er.async_get(self.hass) try: async with self.hass.timeout.async_timeout(timeout, self.domain): for entity in entities: @@ -791,7 +786,7 @@ class EntityPlatform: already_exists = True return (already_exists, restored) - async def _async_add_entity( # noqa: C901 + async def _async_add_entity( self, entity: Entity, update_before_add: bool, @@ -818,12 +813,23 @@ class EntityPlatform: entity.add_to_platform_abort() return - suggested_object_id: str | None = None - entity_name = entity.name if entity_name is UNDEFINED: entity_name = None + suggested_object_id: str | None = None + + # An entity may suggest the entity_id by setting entity_id itself + if not hasattr(entity, "internal_integration_suggested_object_id"): + if entity.entity_id is not None and not valid_entity_id(entity.entity_id): + entity.add_to_platform_abort() + raise HomeAssistantError(f"Invalid entity ID: {entity.entity_id}") + entity.internal_integration_suggested_object_id = ( + split_entity_id(entity.entity_id)[1] + if entity.entity_id is not None + else None + ) + # Get entity_id from unique ID registration if entity.unique_id is not None: registered_entity_id = entity_registry.async_get_entity_id( @@ -852,16 +858,16 @@ class EntityPlatform: entity.add_to_platform_abort() return - device: dev_reg.DeviceEntry | None + device: dr.DeviceEntry | None if self.config_entry: if device_info := entity.device_info: try: - device = dev_reg.async_get(self.hass).async_get_or_create( + device = dr.async_get(self.hass).async_get_or_create( config_entry_id=self.config_entry.entry_id, config_subentry_id=config_subentry_id, **device_info, ) - except dev_reg.DeviceInfoError as exc: + except dr.DeviceInfoError as exc: self.logger.error( "%s: Not adding entity with invalid device info: %s", self.platform_name, @@ -869,28 +875,14 @@ class EntityPlatform: ) entity.add_to_platform_abort() return + + entity.device_entry = device else: device = entity.device_entry else: device = None - calculated_object_id: str | None = None - # An entity may suggest the entity_id by setting entity_id itself - suggested_entity_id: str | None = entity.entity_id - if suggested_entity_id is not None: - suggested_object_id = split_entity_id(entity.entity_id)[1] - if self.entity_namespace is not None: - suggested_object_id = ( - f"{self.entity_namespace} {suggested_object_id}" - ) - if not registered_entity_id and suggested_entity_id is None: - # Do not bother working out a suggested_object_id - # if the entity is already registered as it will - # be ignored. - # - calculated_object_id = async_calculate_suggested_object_id( - entity, device - ) + suggested_object_id, object_id_base = _async_derive_object_ids(entity, self) disabled_by: RegistryEntryDisabler | None = None if not entity.entity_registry_enabled_default: @@ -904,7 +896,6 @@ class EntityPlatform: self.domain, self.platform_name, entity.unique_id, - calculated_object_id=calculated_object_id, capabilities=entity.capability_attributes, config_entry=self.config_entry, config_subentry_id=config_subentry_id, @@ -914,6 +905,7 @@ class EntityPlatform: get_initial_options=entity.get_initial_entity_options, has_entity_name=entity.has_entity_name, hidden_by=hidden_by, + object_id_base=object_id_base, original_device_class=entity.device_class, original_icon=entity.icon, original_name=entity_name, @@ -929,44 +921,24 @@ class EntityPlatform: ) entity.registry_entry = entry - if device: - entity.device_entry = device entity.entity_id = entry.entity_id - else: # entity.unique_id is None - generate_new_entity_id = False + else: # entity.unique_id is None # noqa: PLR5501 # We won't generate an entity ID if the platform has already set one # We will however make sure that platform cannot pick a registered ID - if entity.entity_id is not None and entity_registry.async_is_registered( + if entity.entity_id is None or entity_registry.async_is_registered( entity.entity_id ): - # If entity already registered, convert entity id to suggestion - suggested_object_id = split_entity_id(entity.entity_id)[1] - generate_new_entity_id = True - - # Generate entity ID - if entity.entity_id is None or generate_new_entity_id: - suggested_object_id = ( - suggested_object_id - or entity.suggested_object_id - or DEVICE_DEFAULT_NAME + object_ids = _async_derive_object_ids( + entity, self, fallback_object_id=DEVICE_DEFAULT_NAME ) - - if self.entity_namespace is not None: - suggested_object_id = ( - f"{self.entity_namespace} {suggested_object_id}" - ) - entity.entity_id = entity_registry.async_generate_entity_id( + suggested_object_id = ( + object_ids[0] if object_ids[0] is not None else object_ids[1] + ) + entity.entity_id = entity_registry.async_get_available_entity_id( self.domain, suggested_object_id ) - # Make sure it is valid in case an entity set the value themselves - # Avoid calling valid_entity_id if we already know it is valid - # since it already made it in the registry - if not valid_entity_id(entity.entity_id): - entity.add_to_platform_abort() - raise HomeAssistantError(f"Invalid entity ID: {entity.entity_id}") - already_exists, restored = self._entity_id_already_exists(entity.entity_id) if already_exists: @@ -1234,25 +1206,52 @@ class EntityPlatform: return await self.platform_data.async_load_translations() +@overload +def _async_derive_object_ids( + entity: Entity, platform: EntityPlatform, *, fallback_object_id: None = None +) -> tuple[str | None, str | None]: ... + + +@overload +def _async_derive_object_ids( + entity: Entity, platform: EntityPlatform, *, fallback_object_id: str +) -> tuple[str, None] | tuple[None, str]: ... + + @callback -def async_calculate_suggested_object_id( - entity: Entity, device: dev_reg.DeviceEntry | None -) -> str | None: - """Calculate the suggested object ID for an entity.""" - calculated_object_id: str | None = None - if device and entity.has_entity_name: - device_name = device.name_by_user or device.name - if entity.use_device_name: - calculated_object_id = device_name - else: - calculated_object_id = f"{device_name} {entity.suggested_object_id}" - if not calculated_object_id: - calculated_object_id = entity.suggested_object_id +def _async_derive_object_ids( + entity: Entity, platform: EntityPlatform, *, fallback_object_id: str | None = None +) -> tuple[str | None, str | None]: + """Derive the object IDs for an entity. - if (platform := entity.platform) and platform.entity_namespace is not None: - calculated_object_id = f"{platform.entity_namespace} {calculated_object_id}" + Derives both suggested and base object IDs. + """ + is_base = True + object_id: str | None - return calculated_object_id + if entity.internal_integration_suggested_object_id is not None: + is_base = False + object_id = entity.internal_integration_suggested_object_id + else: + object_id = entity.suggested_object_id + + if not object_id and fallback_object_id is not None: + object_id = fallback_object_id + + if platform.entity_namespace is not None: + is_base = False + if entity.unique_id is not None and not object_id: + object_id = f"{platform.platform_name}_{entity.unique_id}" + object_id = f"{platform.entity_namespace} {object_id}" + + suggested_object_id: str | None = None + object_id_base: str | None = None + if is_base: + object_id_base = object_id + else: + suggested_object_id = object_id + + return suggested_object_id, object_id_base current_platform: ContextVar[EntityPlatform | None] = ContextVar( diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index a6b26af4e02..b04e0109670 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -58,6 +58,7 @@ from .device_registry import ( EVENT_DEVICE_REGISTRY_UPDATED, EventDeviceRegistryUpdatedData, ) +from .frame import ReportBehavior, report_usage from .json import JSON_DUMP, find_paths_unserializable_data, json_bytes, json_fragment from .registry import BaseRegistry, BaseRegistryItems, RegistryIndexType from .singleton import singleton @@ -79,7 +80,7 @@ EVENT_ENTITY_REGISTRY_UPDATED: EventType[EventEntityRegistryUpdatedData] = Event _LOGGER = logging.getLogger(__name__) STORAGE_VERSION_MAJOR = 1 -STORAGE_VERSION_MINOR = 19 +STORAGE_VERSION_MINOR = 20 STORAGE_KEY = "core.entity_registry" CLEANUP_INTERVAL = 3600 * 24 @@ -204,6 +205,7 @@ class RegistryEntry: labels: set[str] = attr.ib(factory=set) modified_at: datetime = attr.ib(factory=utcnow) name: str | None = attr.ib(default=None) + object_id_base: str | None = attr.ib() options: ReadOnlyEntityOptionsType = attr.ib(converter=_protect_entity_options) # As set by integration original_device_class: str | None = attr.ib() @@ -366,6 +368,7 @@ class RegistryEntry: "labels": list(self.labels), "modified_at": self.modified_at, "name": self.name, + "object_id_base": self.object_id_base, "options": self.options, "original_device_class": self.original_device_class, "original_icon": self.original_icon, @@ -410,6 +413,31 @@ class RegistryEntry: hass.states.async_set(self.entity_id, STATE_UNAVAILABLE, attrs) +@callback +def _async_get_full_entity_name( + name: str | None, + *, + device: dr.DeviceEntry | None = None, + platform: str, + unique_id: str, +) -> str: + """Get full name for an entity. + + This includes the device name if appropriate. + """ + if device is not None: + device_name = device.name_by_user or device.name + if not name: + name = device_name + else: + name = f"{device_name} {name}" + + if not name: + name = f"{platform}_{unique_id}" + + return name + + @attr.s(frozen=True, slots=True) class DeletedRegistryEntry: """Deleted Entity Registry Entry.""" @@ -619,6 +647,11 @@ class EntityRegistryStore(storage.Store[dict[str, list[dict[str, Any]]]]): entity["hidden_by_undefined"] = set_to_undefined entity["options_undefined"] = set_to_undefined + if old_minor_version < 20: + # Version 1.20 adds object_id_base to entities + for entity in data["entities"]: + entity["object_id_base"] = entity["original_name"] + if old_major_version > 1: raise NotImplementedError return data @@ -882,9 +915,41 @@ class EntityRegistry(BaseRegistry): current_entity_id: str | None = None, reserved_entity_ids: set[str] | None = None, ) -> str: - """Generate an entity ID that does not conflict. + """Get available entity ID. - Conflicts checked against registered and currently existing entities. + This function is deprecated. Use `async_get_available_entity_id` instead. + + Entity ID conflicts are checked against registered and currently existing entities, + as well as provided `reserved_entity_ids`. + """ + report_usage( + "calls `entity_registry.async_generate_entity_id`, " + "which is deprecated and will be removed in Home Assistant 2027.2; " + "use `entity_registry.async_get_available_entity_id` instead", + core_behavior=ReportBehavior.LOG, + breaks_in_ha_version="2027.2.0", + ) + + return self.async_get_available_entity_id( + domain, + suggested_object_id, + current_entity_id=current_entity_id, + reserved_entity_ids=reserved_entity_ids, + ) + + @callback + def async_get_available_entity_id( + self, + domain: str, + suggested_object_id: str, + *, + current_entity_id: str | None = None, + reserved_entity_ids: set[str] | None = None, + ) -> str: + """Get next available entity ID. + + Entity ID conflicts are checked against registered and currently existing entities, + as well as provided `reserved_entity_ids`. """ preferred_string = f"{domain}.{slugify(suggested_object_id)}" @@ -906,6 +971,86 @@ class EntityRegistry(BaseRegistry): return test_string + def _async_generate_entity_id( + self, + *, + current_entity_id: str | None, + device_id: str | None, + domain: str, + has_entity_name: bool, + name: str | None, + object_id_base: str | None, + platform: str, + reserved_entity_ids: set[str] | None = None, + suggested_object_id: str | None, + unique_id: str, + ) -> str: + """Generate an entity ID, based on all the provided parameters. + + `name` is the name set by the user, not the original name from the integration. + `name` has priority over `suggested_object_id`, which has priority + over `object_id_base`. + `name` and `suggested_object_id` will never be prefixed with the device name, + `object_id_base` will be if `has_entity_name` is True. + + Entity ID conflicts are checked against registered and currently + existing entities, as well as provided `reserved_entity_ids`. + """ + object_id: str | None + use_device = False + if name is not None: + object_id = name + elif suggested_object_id is not None: + object_id = suggested_object_id + else: + object_id = object_id_base + if has_entity_name: + use_device = True + + device = ( + dr.async_get(self.hass).async_get(device_id) + if use_device and device_id is not None + else None + ) + + object_id = _async_get_full_entity_name( + object_id, + device=device, + platform=platform, + unique_id=unique_id, + ) + return self.async_get_available_entity_id( + domain, + object_id, + current_entity_id=current_entity_id, + reserved_entity_ids=reserved_entity_ids, + ) + + @callback + def async_regenerate_entity_id( + self, + entry: RegistryEntry, + *, + reserved_entity_ids: set[str] | None = None, + ) -> str: + """Regenerate an entity ID for an entry. + + Entity ID conflicts are checked against registered and currently existing entities, + as well as provided `reserved_entity_ids`. + """ + return self._async_generate_entity_id( + current_entity_id=entry.entity_id, + device_id=entry.device_id, + domain=entry.domain, + has_entity_name=entry.has_entity_name, + name=entry.name, + object_id_base=entry.object_id_base, + platform=entry.platform, + reserved_entity_ids=reserved_entity_ids, + suggested_object_id=entry.suggested_object_id, + unique_id=entry.unique_id, + ) + @callback def async_get_or_create( self, @@ -913,9 +1058,10 @@ class EntityRegistry(BaseRegistry): platform: str, unique_id: str, *, - # To influence entity ID generation - calculated_object_id: str | None = None, - suggested_object_id: str | None = None, + # Used for entity ID generation, if entity gets created. + # `suggested_object_id` has priority over `object_id_base`. + object_id_base: str | None | UndefinedType = UNDEFINED, + suggested_object_id: str | None | UndefinedType = UNDEFINED, # To disable or hide an entity if it gets created, does not affect # existing entities disabled_by: RegistryEntryDisabler | None = None, @@ -948,7 +1094,7 @@ class EntityRegistry(BaseRegistry): entity_id = self.async_get_entity_id(domain, platform, unique_id) if entity_id: - return self.async_update_entity( + return self._async_update_entity( entity_id, capabilities=capabilities, config_entry_id=config_entry_id, @@ -956,9 +1102,11 @@ class EntityRegistry(BaseRegistry): device_id=device_id, entity_category=entity_category, has_entity_name=has_entity_name, + object_id_base=object_id_base, original_device_class=original_device_class, original_icon=original_icon, original_name=original_name, + suggested_object_id=suggested_object_id, supported_features=supported_features, translation_key=translation_key, unit_of_measurement=unit_of_measurement, @@ -1022,12 +1170,26 @@ class EntityRegistry(BaseRegistry): name = None options = get_initial_options() if get_initial_options else None - if not entity_id: - entity_id = self.async_generate_entity_id( - domain, - suggested_object_id - or calculated_object_id - or f"{platform}_{unique_id}", + def none_if_undefined[_T](value: _T | UndefinedType) -> _T | None: + """Return None if value is UNDEFINED, otherwise return value.""" + return None if value is UNDEFINED else value + + device_id = none_if_undefined(device_id) + has_entity_name_bool = none_if_undefined(has_entity_name) or False + object_id_base = none_if_undefined(object_id_base) + suggested_object_id = none_if_undefined(suggested_object_id) + + if entity_id is None: + entity_id = self._async_generate_entity_id( + current_entity_id=None, + device_id=device_id, + domain=domain, + has_entity_name=has_entity_name_bool, + name=name, + object_id_base=object_id_base, + platform=platform, + suggested_object_id=suggested_object_id, + unique_id=unique_id, ) if ( @@ -1038,10 +1200,6 @@ class EntityRegistry(BaseRegistry): ): disabled_by = RegistryEntryDisabler.INTEGRATION - def none_if_undefined[_T](value: _T | UndefinedType) -> _T | None: - """Return None if value is UNDEFINED, otherwise return value.""" - return None if value is UNDEFINED else value - entry = RegistryEntry( aliases=aliases, area_id=area_id, @@ -1051,16 +1209,17 @@ class EntityRegistry(BaseRegistry): config_subentry_id=none_if_undefined(config_subentry_id), created_at=created_at, device_class=device_class, - device_id=none_if_undefined(device_id), + device_id=device_id, disabled_by=disabled_by, entity_category=none_if_undefined(entity_category), entity_id=entity_id, hidden_by=hidden_by, - has_entity_name=none_if_undefined(has_entity_name) or False, + has_entity_name=has_entity_name_bool, icon=icon, id=entity_registry_id, labels=labels, name=name, + object_id_base=object_id_base, options=options, original_device_class=none_if_undefined(original_device_class), original_icon=none_if_undefined(original_icon), @@ -1255,11 +1414,13 @@ class EntityRegistry(BaseRegistry): name: str | None | UndefinedType = UNDEFINED, new_entity_id: str | UndefinedType = UNDEFINED, new_unique_id: str | UndefinedType = UNDEFINED, + object_id_base: str | None | UndefinedType = UNDEFINED, options: EntityOptionsType | UndefinedType = UNDEFINED, original_device_class: str | None | UndefinedType = UNDEFINED, original_icon: str | None | UndefinedType = UNDEFINED, original_name: str | None | UndefinedType = UNDEFINED, platform: str | None | UndefinedType = UNDEFINED, + suggested_object_id: str | None | UndefinedType = UNDEFINED, supported_features: int | UndefinedType = UNDEFINED, translation_key: str | None | UndefinedType = UNDEFINED, unit_of_measurement: str | None | UndefinedType = UNDEFINED, @@ -1286,11 +1447,13 @@ class EntityRegistry(BaseRegistry): ("has_entity_name", has_entity_name), ("labels", labels), ("name", name), + ("object_id_base", object_id_base), ("options", options), ("original_device_class", original_device_class), ("original_icon", original_icon), ("original_name", original_name), ("platform", platform), + ("suggested_object_id", suggested_object_id), ("supported_features", supported_features), ("translation_key", translation_key), ("unit_of_measurement", unit_of_measurement), @@ -1552,6 +1715,7 @@ class EntityRegistry(BaseRegistry): labels=set(entity["labels"]), modified_at=datetime.fromisoformat(entity["modified_at"]), name=entity["name"], + object_id_base=entity.get("object_id_base"), options=entity["options"], original_device_class=entity["original_device_class"], original_icon=entity["original_icon"], diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 3d7b99d571c..81d91ac8042 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -1601,8 +1601,13 @@ class Script: ): _referenced_extract_ids(data, target, referenced) + elif action == cv.SCRIPT_ACTION_CHECK_CONDITION: + referenced |= condition.async_extract_targets(step, target) + elif action == cv.SCRIPT_ACTION_CHOOSE: for choice in step[CONF_CHOOSE]: + for cond in choice[CONF_CONDITIONS]: + referenced |= condition.async_extract_targets(cond, target) Script._find_referenced_target( target, referenced, choice[CONF_SEQUENCE] ) @@ -1612,6 +1617,8 @@ class Script: ) elif action == cv.SCRIPT_ACTION_IF: + for cond in step[CONF_IF]: + referenced |= condition.async_extract_targets(cond, target) Script._find_referenced_target(target, referenced, step[CONF_THEN]) if CONF_ELSE in step: Script._find_referenced_target(target, referenced, step[CONF_ELSE]) diff --git a/homeassistant/helpers/target.py b/homeassistant/helpers/target.py index b65ed720a82..334b7147e01 100644 --- a/homeassistant/helpers/target.py +++ b/homeassistant/helpers/target.py @@ -2,6 +2,7 @@ from __future__ import annotations +import abc from collections.abc import Callable import dataclasses import logging @@ -268,65 +269,47 @@ def async_extract_referenced_entity_ids( return selected -class TargetStateChangeTracker: - """Helper class to manage state change tracking for targets.""" +class TargetEntityChangeTracker(abc.ABC): + """Helper class to manage entity change tracking for targets.""" def __init__( self, hass: HomeAssistant, target_selection: TargetSelection, - action: Callable[[TargetStateChangedData], Any], entity_filter: Callable[[set[str]], set[str]], ) -> None: """Initialize the state change tracker.""" self._hass = hass self._target_selection = target_selection - self._action = action self._entity_filter = entity_filter - self._state_change_unsub: CALLBACK_TYPE | None = None self._registry_unsubs: list[CALLBACK_TYPE] = [] def async_setup(self) -> Callable[[], None]: """Set up the state change tracking.""" self._setup_registry_listeners() - self._track_entities_state_change() + self._handle_target_update() return self._unsubscribe - def _track_entities_state_change(self) -> None: - """Set up state change tracking for currently selected entities.""" + @abc.abstractmethod + @callback + def _handle_entities_update(self, tracked_entities: set[str]) -> None: + """Called when there's an update to the list of entities of the tracked targets.""" + + @callback + def _handle_target_update(self, event: Event[Any] | None = None) -> None: + """Handle updates in the tracked targets.""" selected = async_extract_referenced_entity_ids( self._hass, self._target_selection, expand_group=False ) - - tracked_entities = self._entity_filter( + filtered_entities = self._entity_filter( selected.referenced | selected.indirectly_referenced ) - - @callback - def state_change_listener(event: Event[EventStateChangedData]) -> None: - """Handle state change events.""" - if ( - event.data["entity_id"] in selected.referenced - or event.data["entity_id"] in selected.indirectly_referenced - ): - self._action(TargetStateChangedData(event, tracked_entities)) - - _LOGGER.debug("Tracking state changes for entities: %s", tracked_entities) - self._state_change_unsub = async_track_state_change_event( - self._hass, tracked_entities, state_change_listener - ) + self._handle_entities_update(filtered_entities) def _setup_registry_listeners(self) -> None: """Set up listeners for registry changes that require resubscription.""" - @callback - def resubscribe_state_change_event(event: Event[Any] | None = None) -> None: - """Resubscribe to state change events when registry changes.""" - if self._state_change_unsub: - self._state_change_unsub() - self._track_entities_state_change() - # Subscribe to registry updates that can change the entities to track: # - Entity registry: entity added/removed; entity labels changed; entity area changed. # - Device registry: device labels changed; device area changed. @@ -336,13 +319,13 @@ class TargetStateChangeTracker: # changes don't affect which entities are tracked. self._registry_unsubs = [ self._hass.bus.async_listen( - er.EVENT_ENTITY_REGISTRY_UPDATED, resubscribe_state_change_event + er.EVENT_ENTITY_REGISTRY_UPDATED, self._handle_target_update ), self._hass.bus.async_listen( - dr.EVENT_DEVICE_REGISTRY_UPDATED, resubscribe_state_change_event + dr.EVENT_DEVICE_REGISTRY_UPDATED, self._handle_target_update ), self._hass.bus.async_listen( - ar.EVENT_AREA_REGISTRY_UPDATED, resubscribe_state_change_event + ar.EVENT_AREA_REGISTRY_UPDATED, self._handle_target_update ), ] @@ -351,6 +334,42 @@ class TargetStateChangeTracker: for registry_unsub in self._registry_unsubs: registry_unsub() self._registry_unsubs.clear() + + +class TargetStateChangeTracker(TargetEntityChangeTracker): + """Helper class to manage state change tracking for targets.""" + + def __init__( + self, + hass: HomeAssistant, + target_selection: TargetSelection, + action: Callable[[TargetStateChangedData], Any], + entity_filter: Callable[[set[str]], set[str]], + ) -> None: + """Initialize the state change tracker.""" + super().__init__(hass, target_selection, entity_filter) + self._action = action + self._state_change_unsub: CALLBACK_TYPE | None = None + + def _handle_entities_update(self, tracked_entities: set[str]) -> None: + """Handle the tracked entities.""" + + @callback + def state_change_listener(event: Event[EventStateChangedData]) -> None: + """Handle state change events.""" + if event.data["entity_id"] in tracked_entities: + self._action(TargetStateChangedData(event, tracked_entities)) + + _LOGGER.debug("Tracking state changes for entities: %s", tracked_entities) + if self._state_change_unsub: + self._state_change_unsub() + self._state_change_unsub = async_track_state_change_event( + self._hass, tracked_entities, state_change_listener + ) + + def _unsubscribe(self) -> None: + """Unsubscribe from all events.""" + super()._unsubscribe() if self._state_change_unsub: self._state_change_unsub() self._state_change_unsub = None diff --git a/homeassistant/helpers/trigger.py b/homeassistant/helpers/trigger.py index baa0e379de0..225c6bcbc66 100644 --- a/homeassistant/helpers/trigger.py +++ b/homeassistant/helpers/trigger.py @@ -594,6 +594,8 @@ class EntityNumericalStateAttributeChangedTriggerBase(EntityTriggerBase): _above: None | float | str _below: None | float | str + _converter: Callable[[Any], float] = float + def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None: """Initialize the state trigger.""" super().__init__(hass, config) @@ -616,7 +618,7 @@ class EntityNumericalStateAttributeChangedTriggerBase(EntityTriggerBase): return False try: - current_value = float(_attribute_value) + current_value = self._converter(_attribute_value) except (TypeError, ValueError): # Attribute is not a valid number, don't trigger return False @@ -706,6 +708,8 @@ class EntityNumericalStateAttributeCrossedThresholdTriggerBase(EntityTriggerBase _upper_limit: float | str | None = None _threshold_type: ThresholdType + _converter: Callable[[Any], float] = float + def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None: """Initialize the state trigger.""" super().__init__(hass, config) @@ -741,7 +745,7 @@ class EntityNumericalStateAttributeCrossedThresholdTriggerBase(EntityTriggerBase return False try: - current_value = float(_attribute_value) + current_value = self._converter(_attribute_value) except (TypeError, ValueError): # Attribute is not a valid number, don't trigger return False diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 35c1dce2227..98fd7c385b6 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -2,7 +2,7 @@ aiodhcpwatcher==1.2.1 aiodiscover==2.7.1 -aiodns==3.6.1 +aiodns==4.0.0 aiohasupervisor==0.3.3 aiohttp-asyncmdnsresolver==0.1.1 aiohttp-fast-zlib==0.3.0 @@ -36,10 +36,10 @@ fnv-hash-fast==1.6.0 go2rtc-client==0.4.0 ha-ffmpeg==3.2.2 habluetooth==5.8.0 -hass-nabucasa==1.7.0 +hass-nabucasa==1.11.0 hassil==3.5.0 home-assistant-bluetooth==1.13.1 -home-assistant-frontend==20260107.0 +home-assistant-frontend==20260107.2 home-assistant-intents==2026.1.6 httpx==0.28.1 ifaddr==0.2.0 @@ -53,10 +53,10 @@ Pillow==12.0.0 propcache==0.4.1 psutil-home-assistant==0.0.1 PyJWT==2.10.1 -PyNaCl==1.6.0 +pymicro-vad==1.0.1 +PyNaCl==1.6.2 pyOpenSSL==25.3.0 pyserial==3.5 -pysilero-vad==3.1.0 pyspeex-noise==1.0.2 python-slugify==8.0.4 PyTurboJPEG==1.8.0 diff --git a/homeassistant/requirements.py b/homeassistant/requirements.py index 6023ed7a4e6..75d3fbf46d1 100644 --- a/homeassistant/requirements.py +++ b/homeassistant/requirements.py @@ -9,8 +9,6 @@ import logging import os from typing import Any -from packaging.requirements import Requirement - from .core import HomeAssistant, callback from .exceptions import HomeAssistantError from .helpers import singleton @@ -260,8 +258,13 @@ class RequirementsManager: """ if DEPRECATED_PACKAGES or self.hass.config.skip_pip_packages: all_requirements = { - requirement_string: Requirement(requirement_string) + requirement_string: requirement_details for requirement_string in requirements + if ( + requirement_details := pkg_util.parse_requirement_safe( + requirement_string + ) + ) } if DEPRECATED_PACKAGES: for requirement_string, requirement_details in all_requirements.items(): @@ -272,9 +275,12 @@ class RequirementsManager: "" if is_built_in else "custom ", name, f"has requirement '{requirement_string}' which {reason}", - f"This will stop working in Home Assistant {breaks_in_ha_version}, please" - if breaks_in_ha_version - else "Please", + ( + "This will stop working in Home Assistant " + f"{breaks_in_ha_version}, please" + if breaks_in_ha_version + else "Please" + ), async_suggest_report_issue( self.hass, integration_domain=name ), diff --git a/homeassistant/strings.json b/homeassistant/strings.json index 20b56507b9d..b32420b974b 100644 --- a/homeassistant/strings.json +++ b/homeassistant/strings.json @@ -85,6 +85,9 @@ "timeout_connect": "Timeout establishing connection", "unknown": "Unexpected error" }, + "initiate_flow": { + "account": "Add account" + }, "title": { "oauth2_pick_implementation": "Pick authentication method", "reauth": "Authentication expired for {name}", diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index 2c0ed363eef..eebcdb2bba6 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -44,6 +44,39 @@ def get_installed_versions(specifiers: set[str]) -> set[str]: return {specifier for specifier in specifiers if is_installed(specifier)} +def parse_requirement_safe(requirement_str: str) -> Requirement | None: + """Parse a requirement string into a Requirement object. + + expected input is a pip compatible package specifier (requirement string) + e.g. "package==1.0.0" or "package>=1.0.0,<2.0.0" or "package@git+https://..." + + For backward compatibility, it also accepts a URL with a fragment + e.g. "git+https://github.com/pypa/pip#pip>=1" + + Returns None on a badly-formed requirement string. + """ + try: + return Requirement(requirement_str) + except InvalidRequirement: + if "#" not in requirement_str: + _LOGGER.error("Invalid requirement '%s'", requirement_str) + return None + + # This is likely a URL with a fragment + # example: git+https://github.com/pypa/pip#pip>=1 + + # fragment support was originally used to install zip files, and + # we no longer do this in Home Assistant. However, custom + # components started using it to install packages from git + # urls which would make it would be a breaking change to + # remove it. + try: + return Requirement(urlparse(requirement_str).fragment) + except InvalidRequirement: + _LOGGER.error("Invalid requirement '%s'", requirement_str) + return None + + def is_installed(requirement_str: str) -> bool: """Check if a package is installed and will be loaded when we import it. @@ -56,26 +89,8 @@ def is_installed(requirement_str: str) -> bool: Returns True when the requirement is met. Returns False when the package is not installed or doesn't meet req. """ - try: - req = Requirement(requirement_str) - except InvalidRequirement: - if "#" not in requirement_str: - _LOGGER.error("Invalid requirement '%s'", requirement_str) - return False - - # This is likely a URL with a fragment - # example: git+https://github.com/pypa/pip#pip>=1 - - # fragment support was originally used to install zip files, and - # we no longer do this in Home Assistant. However, custom - # components started using it to install packages from git - # urls which would make it would be a breaking change to - # remove it. - try: - req = Requirement(urlparse(requirement_str).fragment) - except InvalidRequirement: - _LOGGER.error("Invalid requirement '%s'", requirement_str) - return False + if (req := parse_requirement_safe(requirement_str)) is None: + return False try: if (installed_version := version(req.name)) is None: diff --git a/homeassistant/util/unit_conversion.py b/homeassistant/util/unit_conversion.py index 68b27b98cd8..daae62861a4 100644 --- a/homeassistant/util/unit_conversion.py +++ b/homeassistant/util/unit_conversion.py @@ -103,6 +103,9 @@ _AMBIENT_IDEAL_GAS_MOLAR_VOLUME = ( # m3⋅mol⁻¹ ) # Molar masses in g⋅mol⁻¹ _CARBON_MONOXIDE_MOLAR_MASS = 28.01 +_NITROGEN_DIOXIDE_MOLAR_MASS = 46.0055 +_OZONE_MOLAR_MASS = 48.00 +_SULPHUR_DIOXIDE_MOLAR_MASS = 64.066 class BaseUnitConverter: @@ -193,6 +196,7 @@ class CarbonMonoxideConcentrationConverter(BaseUnitConverter): UNIT_CLASS = "carbon_monoxide" _UNIT_CONVERSION: dict[str | None, float] = { + CONCENTRATION_PARTS_PER_BILLION: 1e9, CONCENTRATION_PARTS_PER_MILLION: 1e6, CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER: ( _CARBON_MONOXIDE_MOLAR_MASS / _AMBIENT_IDEAL_GAS_MOLAR_VOLUME * 1e3 @@ -202,12 +206,45 @@ class CarbonMonoxideConcentrationConverter(BaseUnitConverter): ), } VALID_UNITS = { + CONCENTRATION_PARTS_PER_BILLION, CONCENTRATION_PARTS_PER_MILLION, CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, } +class NitrogenDioxideConcentrationConverter(BaseUnitConverter): + """Convert nitrogen dioxide ratio to mass per volume.""" + + UNIT_CLASS = "nitrogen_dioxide" + _UNIT_CONVERSION: dict[str | None, float] = { + CONCENTRATION_PARTS_PER_BILLION: 1e9, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: ( + _NITROGEN_DIOXIDE_MOLAR_MASS / _AMBIENT_IDEAL_GAS_MOLAR_VOLUME * 1e6 + ), + } + VALID_UNITS = { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + } + + +class SulphurDioxideConcentrationConverter(BaseUnitConverter): + """Convert sulphur dioxide ratio to mass per volume.""" + + UNIT_CLASS = "sulphur_dioxide" + _UNIT_CONVERSION: dict[str | None, float] = { + CONCENTRATION_PARTS_PER_BILLION: 1e9, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: ( + _SULPHUR_DIOXIDE_MOLAR_MASS / _AMBIENT_IDEAL_GAS_MOLAR_VOLUME * 1e6 + ), + } + VALID_UNITS = { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + } + + class DataRateConverter(BaseUnitConverter): """Utility to convert data rate values.""" @@ -526,6 +563,22 @@ class ReactivePowerConverter(BaseUnitConverter): } +class OzoneConcentrationConverter(BaseUnitConverter): + """Convert ozone ratio to mass per volume.""" + + UNIT_CLASS = "ozone" + _UNIT_CONVERSION: dict[str | None, float] = { + CONCENTRATION_PARTS_PER_BILLION: 1e9, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER: ( + _OZONE_MOLAR_MASS / _AMBIENT_IDEAL_GAS_MOLAR_VOLUME * 1e6 + ), + } + VALID_UNITS = { + CONCENTRATION_PARTS_PER_BILLION, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + } + + class SpeedConverter(BaseUnitConverter): """Utility to convert speed values.""" diff --git a/mypy.ini b/mypy.ini index e21f8fd44c3..da80d719894 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3826,6 +3826,16 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.pooldose.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.portainer.*] check_untyped_defs = true disallow_incomplete_defs = true @@ -4296,6 +4306,16 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.saunum.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.scene.*] check_untyped_defs = true disallow_incomplete_defs = true diff --git a/pylint/plugins/hass_enforce_type_hints.py b/pylint/plugins/hass_enforce_type_hints.py index 4b22d1284d7..54b755fc98c 100644 --- a/pylint/plugins/hass_enforce_type_hints.py +++ b/pylint/plugins/hass_enforce_type_hints.py @@ -16,7 +16,7 @@ from homeassistant.const import Platform if TYPE_CHECKING: # InferenceResult is available only from astroid >= 2.12.0 - # pre-commit should still work on out of date environments + # prek should still work on out of date environments from astroid.typing import InferenceResult _COMMON_ARGUMENTS: dict[str, list[str]] = { @@ -168,7 +168,6 @@ _TEST_FIXTURES: dict[str, list[str] | str] = { "service_calls": "list[ServiceCall]", "snapshot": "SnapshotAssertion", "socket_enabled": "None", - "stub_blueprint_populate": "None", "tmp_path": "Path", "tmpdir": "py.path.local", "tts_mutagen_mock": "MagicMock", @@ -700,6 +699,7 @@ _ENTITY_MATCH: list[TypeHintMatch] = [ TypeHintMatch( function_name="device_class", return_type=["str", None], + mandatory=True, ), TypeHintMatch( function_name="unit_of_measurement", @@ -931,6 +931,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["BinarySensorDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="is_on", @@ -954,6 +955,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["ButtonDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="press", @@ -1222,6 +1224,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="preset_mode", return_type=["str", None], + mandatory=True, ), TypeHintMatch( function_name="preset_modes", @@ -1366,6 +1369,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["CoverDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="current_cover_position", @@ -1598,6 +1602,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="preset_mode", return_type=["str", None], + mandatory=True, ), TypeHintMatch( function_name="preset_modes", @@ -1991,6 +1996,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["MediaPlayerDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="state", @@ -2314,6 +2320,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { kwargs_type="Any", return_type=None, has_async_counterpart=True, + mandatory=True, ), ], ), @@ -2333,6 +2340,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["NumberDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="capability_attributes", @@ -2507,14 +2515,17 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["SensorDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="state_class", return_type=["SensorStateClass", "str", None], + mandatory=True, ), TypeHintMatch( function_name="last_reset", return_type=["datetime", None], + mandatory=True, ), TypeHintMatch( function_name="native_value", @@ -2631,6 +2642,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["SwitchDeviceClass", None], + mandatory=True, ), ], ), @@ -2735,6 +2747,7 @@ _INHERITANCE_MATCH: dict[str, list[ClassTypeHintMatch]] = { TypeHintMatch( function_name="device_class", return_type=["UpdateDeviceClass", None], + mandatory=True, ), TypeHintMatch( function_name="in_progress", diff --git a/pyproject.toml b/pyproject.toml index c5bcf7dca57..bb5cb34f3eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ ] requires-python = ">=3.13.2" dependencies = [ - "aiodns==3.6.1", + "aiodns==4.0.0", # Integrations may depend on hassio integration without listing it to # change behavior based on presence of supervisor. Deprecated with #127228 # Lib can be removed with 2025.11 @@ -48,7 +48,7 @@ dependencies = [ "fnv-hash-fast==1.6.0", # hass-nabucasa is imported by helpers which don't depend on the cloud # integration - "hass-nabucasa==1.7.0", + "hass-nabucasa==1.11.0", # When bumping httpx, please check the version pins of # httpcore, anyio, and h11 in gen_requirements_all "httpx==0.28.1", diff --git a/requirements.txt b/requirements.txt index d7f3ca26675..754d7543fb0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ -c homeassistant/package_constraints.txt # Home Assistant Core -aiodns==3.6.1 +aiodns==4.0.0 aiohasupervisor==0.3.3 aiohttp-asyncmdnsresolver==0.1.1 aiohttp-fast-zlib==0.3.0 @@ -24,7 +24,7 @@ cronsim==2.7 cryptography==46.0.2 fnv-hash-fast==1.6.0 ha-ffmpeg==3.2.2 -hass-nabucasa==1.7.0 +hass-nabucasa==1.11.0 hassil==3.5.0 home-assistant-bluetooth==1.13.1 home-assistant-intents==2026.1.6 @@ -39,8 +39,8 @@ Pillow==12.0.0 propcache==0.4.1 psutil-home-assistant==0.0.1 PyJWT==2.10.1 +pymicro-vad==1.0.1 pyOpenSSL==25.3.0 -pysilero-vad==3.1.0 pyspeex-noise==1.0.2 python-slugify==8.0.4 PyTurboJPEG==1.8.0 diff --git a/requirements_all.txt b/requirements_all.txt index a1b5c0d86ef..db0a235631e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -70,7 +70,7 @@ PyMicroBot==0.0.23 # homeassistant.components.mobile_app # homeassistant.components.owntracks -PyNaCl==1.6.0 +PyNaCl==1.6.2 # homeassistant.auth.mfa_modules.totp # homeassistant.components.homekit @@ -80,7 +80,7 @@ PyQRCode==1.2.1 PyRMVtransport==0.3.3 # homeassistant.components.sunricher_dali -PySrDaliGateway==0.18.0 +PySrDaliGateway==0.19.3 # homeassistant.components.switchbot PySwitchbot==0.76.0 @@ -187,7 +187,7 @@ aioairq==0.4.7 aioairzone-cloud==0.7.2 # homeassistant.components.airzone -aioairzone==1.0.4 +aioairzone==1.0.5 # homeassistant.components.alexa_devices aioamazondevices==11.0.2 @@ -231,7 +231,7 @@ aiodhcpwatcher==1.2.1 aiodiscover==2.7.1 # homeassistant.components.dnsip -aiodns==3.6.1 +aiodns==4.0.0 # homeassistant.components.duke_energy aiodukeenergy==0.3.0 @@ -319,7 +319,7 @@ aiolookin==1.0.0 aiolyric==2.0.2 # homeassistant.components.mealie -aiomealie==1.1.1 +aiomealie==1.2.0 # homeassistant.components.modern_forms aiomodernforms==0.1.8 @@ -334,7 +334,7 @@ aionanoleaf==0.2.1 aionotion==2024.03.0 # homeassistant.components.ntfy -aiontfy==0.6.1 +aiontfy==0.7.0 # homeassistant.components.nut aionut==4.3.4 @@ -703,7 +703,7 @@ brottsplatskartan==1.0.5 brunt==1.2.0 # homeassistant.components.bthome -bthome-ble==3.17.0 +bthome-ble==3.16.0 # homeassistant.components.bt_home_hub_5 bthomehub5-devicelist==0.1.1 @@ -739,7 +739,7 @@ colorlog==6.10.1 colorthief==0.2.1 # homeassistant.components.compit -compit-inext-api==0.3.4 +compit-inext-api==0.4.2 # homeassistant.components.concord232 concord232==0.15.1 @@ -785,7 +785,6 @@ decora-wifi==1.4 deebot-client==17.0.1 # homeassistant.components.ihc -# homeassistant.components.namecheapdns # homeassistant.components.ohmconnect # homeassistant.components.sonos defusedxml==0.7.1 @@ -842,7 +841,7 @@ dynalite-panel==0.0.4 eagle100==0.1.1 # homeassistant.components.easyenergy -easyenergy==2.1.2 +easyenergy==2.2.0 # homeassistant.components.ebusd ebusdpy==0.0.17 @@ -1011,7 +1010,7 @@ freebox-api==1.2.2 freesms==0.2.0 # homeassistant.components.fressnapf_tracker -fressnapftracker==0.2.0 +fressnapftracker==0.2.1 # homeassistant.components.fritz # homeassistant.components.fritzbox_callmonitor @@ -1093,7 +1092,7 @@ google-cloud-speech==2.31.1 google-cloud-texttospeech==2.25.1 # homeassistant.components.google_generative_ai_conversation -google-genai==1.56.0 +google-genai==1.59.0 # homeassistant.components.google_travel_time google-maps-routing==0.6.15 @@ -1105,7 +1104,7 @@ google-nest-sdm==9.1.2 google-photos-library-api==0.12.1 # homeassistant.components.google_air_quality -google_air_quality_api==2.1.2 +google_air_quality_api==3.0.0 # homeassistant.components.slide # homeassistant.components.slide_local @@ -1127,7 +1126,7 @@ gpiozero==1.6.2 gps3==0.33.3 # homeassistant.components.gree -greeclimate==2.1.0 +greeclimate==2.1.1 # homeassistant.components.greeneye_monitor greeneye_monitor==3.0.3 @@ -1172,7 +1171,7 @@ habluetooth==5.8.0 hanna-cloud==0.0.7 # homeassistant.components.cloud -hass-nabucasa==1.7.0 +hass-nabucasa==1.11.0 # homeassistant.components.splunk hass-splunk==0.1.1 @@ -1216,7 +1215,7 @@ hole==0.9.0 holidays==0.84 # homeassistant.components.frontend -home-assistant-frontend==20260107.0 +home-assistant-frontend==20260107.2 # homeassistant.components.conversation home-assistant-intents==2026.1.6 @@ -1352,7 +1351,7 @@ kiwiki-client==0.1.1 knocki==0.4.2 # homeassistant.components.knx -knx-frontend==2025.12.30.151231 +knx-frontend==2026.1.15.112308 # homeassistant.components.konnected konnected==1.2.0 @@ -1455,7 +1454,7 @@ mbddns==0.1.2 mcp==1.14.1 # homeassistant.components.minecraft_server -mcstatus==12.0.6 +mcstatus==12.1.0 # homeassistant.components.meater meater-python==0.0.8 @@ -1647,7 +1646,7 @@ omnilogic==0.4.5 ondilo==0.5.0 # homeassistant.components.onedrive -onedrive-personal-sdk==0.0.17 +onedrive-personal-sdk==0.1.1 # homeassistant.components.onvif onvif-zeep-async==4.0.4 @@ -1684,7 +1683,7 @@ openwrt-luci-rpc==1.1.17 openwrt-ubus-rpc==0.0.2 # homeassistant.components.opower -opower==0.16.1 +opower==0.16.4 # homeassistant.components.oralb oralb-ble==1.0.2 @@ -1867,7 +1866,7 @@ pyRFXtrx==0.31.1 pySDCP==1 # homeassistant.components.tibber -pyTibber==0.34.1 +pyTibber==0.35.0 # homeassistant.components.dlink pyW215==0.8.0 @@ -2022,7 +2021,7 @@ pyegps==0.2.5 pyemoncms==0.1.3 # homeassistant.components.enphase_envoy -pyenphase==2.4.2 +pyenphase==2.4.3 # homeassistant.components.envisalink pyenvisalink==4.7 @@ -2046,7 +2045,7 @@ pyfibaro==0.8.3 pyfido==2.1.2 # homeassistant.components.firefly_iii -pyfirefly==0.1.10 +pyfirefly==0.1.12 # homeassistant.components.fireservicerota pyfireservicerota==0.0.46 @@ -2097,7 +2096,7 @@ pyhomeworks==1.1.2 pyialarm==2.2.0 # homeassistant.components.icloud -pyicloud==2.2.0 +pyicloud==2.3.0 # homeassistant.components.insteon pyinsteon==1.6.4 @@ -2133,7 +2132,7 @@ pyitachip2ir==0.0.7 pyituran==0.1.5 # homeassistant.components.jvc_projector -pyjvcprojector==1.1.3 +pyjvcprojector==2.0.0 # homeassistant.components.kaleidescape pykaleidescape==1.0.2 @@ -2148,7 +2147,7 @@ pykmtronic==0.3.0 pykodi==0.2.7 # homeassistant.components.kostal_plenticore -pykoplenti==1.3.0 +pykoplenti==1.5.0 # homeassistant.components.kraken pykrakenapi==0.1.8 @@ -2201,6 +2200,9 @@ pymediaroom==0.6.5.4 # homeassistant.components.meteoclimatic pymeteoclimatic==0.1.0 +# homeassistant.components.assist_pipeline +pymicro-vad==1.0.1 + # homeassistant.components.miele pymiele==0.6.1 @@ -2232,7 +2234,7 @@ pynetgear==0.10.10 pynetio==0.1.9.1 # homeassistant.components.nina -pynina==0.3.6 +pynina==1.0.2 # homeassistant.components.nintendo_parental_controls pynintendoauth==1.0.2 @@ -2318,7 +2320,7 @@ pyplaato==0.0.19 pypoint==3.0.0 # homeassistant.components.portainer -pyportainer==1.0.22 +pyportainer==1.0.23 # homeassistant.components.probe_plus pyprobeplus==1.1.2 @@ -2375,7 +2377,7 @@ pysabnzbd==1.1.1 pysaj==0.0.16 # homeassistant.components.saunum -pysaunum==0.1.0 +pysaunum==0.3.0 # homeassistant.components.schlage pyschlage==2025.9.0 @@ -2408,9 +2410,6 @@ pysiaalarm==3.1.1 # homeassistant.components.signal_messenger pysignalclirestapi==0.3.24 -# homeassistant.components.assist_pipeline -pysilero-vad==3.1.0 - # homeassistant.components.sky_hub pyskyqhub==0.1.4 @@ -2481,7 +2480,7 @@ python-awair==0.2.5 python-blockchain-api==0.0.2 # homeassistant.components.bsblan -python-bsblan==3.1.6 +python-bsblan==4.1.0 # homeassistant.components.citybikes python-citybikes==0.3.3 @@ -2520,7 +2519,7 @@ python-google-weather-api==0.0.4 python-homeassistant-analytics==0.9.0 # homeassistant.components.homewizard -python-homewizard-energy==10.0.0 +python-homewizard-energy==10.0.1 # homeassistant.components.hp_ilo python-hpilo==4.4.3 @@ -2575,7 +2574,7 @@ python-overseerr==0.8.0 python-picnic-api2==1.3.1 # homeassistant.components.pooldose -python-pooldose==0.8.1 +python-pooldose==0.8.2 # homeassistant.components.rabbitair python-rabbitair==0.0.8 @@ -2596,7 +2595,7 @@ python-snoo==0.8.3 python-songpal==0.16.2 # homeassistant.components.tado -python-tado==0.18.15 +python-tado==0.18.16 # homeassistant.components.technove python-technove==2.0.0 @@ -2708,7 +2707,7 @@ qbittorrent-api==2024.9.67 qbusmqttapi==1.4.2 # homeassistant.components.qingping -qingping-ble==1.0.1 +qingping-ble==1.1.0 # homeassistant.components.qnap qnapstats==0.4.0 @@ -2956,7 +2955,7 @@ surepy==0.9.0 swisshydrodata==0.1.0 # homeassistant.components.switchbot_cloud -switchbot-api==2.9.0 +switchbot-api==2.10.0 # homeassistant.components.synology_srm synology-srm==0.2.0 @@ -2991,7 +2990,7 @@ temperusb==1.6.1 # homeassistant.components.tesla_fleet # homeassistant.components.teslemetry # homeassistant.components.tessie -tesla-fleet-api==1.3.2 +tesla-fleet-api==1.4.2 # homeassistant.components.powerwall tesla-powerwall==0.5.2 @@ -3081,7 +3080,7 @@ typedmonarchmoney==0.4.4 uasiren==0.0.1 # homeassistant.components.unifiprotect -uiprotect==8.0.0 +uiprotect==10.0.0 # homeassistant.components.landisgyr_heat_meter ultraheat-api==0.5.7 @@ -3116,7 +3115,7 @@ uvcclient==0.12.1 vacuum-map-parser-roborock==0.1.4 # homeassistant.components.vallox -vallox-websocket-api==5.3.0 +vallox-websocket-api==6.0.0 # homeassistant.components.vegehub vegehub==0.1.26 @@ -3146,7 +3145,7 @@ visionpluspython==1.0.2 vobject==0.9.9 # homeassistant.components.voip -voip-utils==0.3.4 +voip-utils==0.3.5 # homeassistant.components.volkszaehler volkszaehler==0.4.0 @@ -3171,7 +3170,7 @@ wallbox==0.9.0 watchdog==6.0.0 # homeassistant.components.waterfurnace -waterfurnace==1.2.0 +waterfurnace==1.4.0 # homeassistant.components.watergate watergate-local-api==2025.1.0 @@ -3216,10 +3215,10 @@ wsdot==0.0.1 wyoming==1.7.2 # homeassistant.components.xiaomi_ble -xiaomi-ble==1.4.1 +xiaomi-ble==1.5.0 # homeassistant.components.knx -xknx==3.13.0 +xknx==3.14.0 # homeassistant.components.knx xknxproject==3.8.2 @@ -3292,7 +3291,7 @@ ziggo-mediabox-xl==1.1.0 zm-py==0.5.4 # homeassistant.components.zwave_js -zwave-js-server-python==0.67.1 +zwave-js-server-python==0.68.0 # homeassistant.components.zwave_me zwave-me-ws==0.4.3 diff --git a/requirements_test.txt b/requirements_test.txt index 7126bb9371a..0e66d530eff 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -15,7 +15,7 @@ librt==0.2.1 license-expression==30.4.3 mock-open==1.4.0 mypy-dev==1.19.0a4 -pre-commit==4.2.0 +prek==0.2.28 pydantic==2.12.2 pylint==4.0.1 pylint-per-file-ignores==1.4.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9abf72afe0a..a7879b77798 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -70,7 +70,7 @@ PyMicroBot==0.0.23 # homeassistant.components.mobile_app # homeassistant.components.owntracks -PyNaCl==1.6.0 +PyNaCl==1.6.2 # homeassistant.auth.mfa_modules.totp # homeassistant.components.homekit @@ -80,7 +80,7 @@ PyQRCode==1.2.1 PyRMVtransport==0.3.3 # homeassistant.components.sunricher_dali -PySrDaliGateway==0.18.0 +PySrDaliGateway==0.19.3 # homeassistant.components.switchbot PySwitchbot==0.76.0 @@ -178,7 +178,7 @@ aioairq==0.4.7 aioairzone-cloud==0.7.2 # homeassistant.components.airzone -aioairzone==1.0.4 +aioairzone==1.0.5 # homeassistant.components.alexa_devices aioamazondevices==11.0.2 @@ -222,7 +222,7 @@ aiodhcpwatcher==1.2.1 aiodiscover==2.7.1 # homeassistant.components.dnsip -aiodns==3.6.1 +aiodns==4.0.0 # homeassistant.components.duke_energy aiodukeenergy==0.3.0 @@ -304,7 +304,7 @@ aiolookin==1.0.0 aiolyric==2.0.2 # homeassistant.components.mealie -aiomealie==1.1.1 +aiomealie==1.2.0 # homeassistant.components.modern_forms aiomodernforms==0.1.8 @@ -319,7 +319,7 @@ aionanoleaf==0.2.1 aionotion==2024.03.0 # homeassistant.components.ntfy -aiontfy==0.6.1 +aiontfy==0.7.0 # homeassistant.components.nut aionut==4.3.4 @@ -633,7 +633,7 @@ brottsplatskartan==1.0.5 brunt==1.2.0 # homeassistant.components.bthome -bthome-ble==3.17.0 +bthome-ble==3.16.0 # homeassistant.components.buienradar buienradar==1.0.6 @@ -654,7 +654,7 @@ colorlog==6.10.1 colorthief==0.2.1 # homeassistant.components.compit -compit-inext-api==0.3.4 +compit-inext-api==0.4.2 # homeassistant.components.concord232 concord232==0.15.1 @@ -694,7 +694,6 @@ debugpy==1.8.17 deebot-client==17.0.1 # homeassistant.components.ihc -# homeassistant.components.namecheapdns # homeassistant.components.ohmconnect # homeassistant.components.sonos defusedxml==0.7.1 @@ -748,7 +747,7 @@ dynalite-panel==0.0.4 eagle100==0.1.1 # homeassistant.components.easyenergy -easyenergy==2.1.2 +easyenergy==2.2.0 # homeassistant.components.egauge egauge-async==0.4.0 @@ -890,7 +889,7 @@ forecast-solar==4.2.0 freebox-api==1.2.2 # homeassistant.components.fressnapf_tracker -fressnapftracker==0.2.0 +fressnapftracker==0.2.1 # homeassistant.components.fritz # homeassistant.components.fritzbox_callmonitor @@ -969,7 +968,7 @@ google-cloud-speech==2.31.1 google-cloud-texttospeech==2.25.1 # homeassistant.components.google_generative_ai_conversation -google-genai==1.56.0 +google-genai==1.59.0 # homeassistant.components.google_travel_time google-maps-routing==0.6.15 @@ -981,7 +980,7 @@ google-nest-sdm==9.1.2 google-photos-library-api==0.12.1 # homeassistant.components.google_air_quality -google_air_quality_api==2.1.2 +google_air_quality_api==3.0.0 # homeassistant.components.slide # homeassistant.components.slide_local @@ -1000,7 +999,7 @@ govee-local-api==2.3.0 gps3==0.33.3 # homeassistant.components.gree -greeclimate==2.1.0 +greeclimate==2.1.1 # homeassistant.components.greeneye_monitor greeneye_monitor==3.0.3 @@ -1042,7 +1041,7 @@ habluetooth==5.8.0 hanna-cloud==0.0.7 # homeassistant.components.cloud -hass-nabucasa==1.7.0 +hass-nabucasa==1.11.0 # homeassistant.components.assist_satellite # homeassistant.components.conversation @@ -1074,7 +1073,7 @@ hole==0.9.0 holidays==0.84 # homeassistant.components.frontend -home-assistant-frontend==20260107.0 +home-assistant-frontend==20260107.2 # homeassistant.components.conversation home-assistant-intents==2026.1.6 @@ -1186,7 +1185,7 @@ kegtron-ble==1.0.2 knocki==0.4.2 # homeassistant.components.knx -knx-frontend==2025.12.30.151231 +knx-frontend==2026.1.15.112308 # homeassistant.components.konnected konnected==1.2.0 @@ -1268,7 +1267,7 @@ mbddns==0.1.2 mcp==1.14.1 # homeassistant.components.minecraft_server -mcstatus==12.0.6 +mcstatus==12.1.0 # homeassistant.components.meater meater-python==0.0.8 @@ -1430,7 +1429,7 @@ omnilogic==0.4.5 ondilo==0.5.0 # homeassistant.components.onedrive -onedrive-personal-sdk==0.0.17 +onedrive-personal-sdk==0.1.1 # homeassistant.components.onvif onvif-zeep-async==4.0.4 @@ -1458,7 +1457,7 @@ openrgb-python==0.3.6 openwebifpy==4.3.1 # homeassistant.components.opower -opower==0.16.1 +opower==0.16.4 # homeassistant.components.oralb oralb-ble==1.0.2 @@ -1523,6 +1522,9 @@ prometheus-client==0.21.0 # homeassistant.components.prowl prowlpy==1.1.1 +# homeassistant.components.proxmoxve +proxmoxer==2.0.1 + # homeassistant.components.hardware # homeassistant.components.recorder # homeassistant.components.systemmonitor @@ -1598,7 +1600,7 @@ pyHomee==1.3.8 pyRFXtrx==0.31.1 # homeassistant.components.tibber -pyTibber==0.34.1 +pyTibber==0.35.0 # homeassistant.components.dlink pyW215==0.8.0 @@ -1717,7 +1719,7 @@ pyegps==0.2.5 pyemoncms==0.1.3 # homeassistant.components.enphase_envoy -pyenphase==2.4.2 +pyenphase==2.4.3 # homeassistant.components.everlights pyeverlights==0.1.0 @@ -1735,7 +1737,7 @@ pyfibaro==0.8.3 pyfido==2.1.2 # homeassistant.components.firefly_iii -pyfirefly==0.1.10 +pyfirefly==0.1.12 # homeassistant.components.fireservicerota pyfireservicerota==0.0.46 @@ -1777,7 +1779,7 @@ pyhomeworks==1.1.2 pyialarm==2.2.0 # homeassistant.components.icloud -pyicloud==2.2.0 +pyicloud==2.3.0 # homeassistant.components.insteon pyinsteon==1.6.4 @@ -1804,7 +1806,7 @@ pyisy==3.4.1 pyituran==0.1.5 # homeassistant.components.jvc_projector -pyjvcprojector==1.1.3 +pyjvcprojector==2.0.0 # homeassistant.components.kaleidescape pykaleidescape==1.0.2 @@ -1819,7 +1821,7 @@ pykmtronic==0.3.0 pykodi==0.2.7 # homeassistant.components.kostal_plenticore -pykoplenti==1.3.0 +pykoplenti==1.5.0 # homeassistant.components.kraken pykrakenapi==0.1.8 @@ -1863,6 +1865,9 @@ pymata-express==1.19 # homeassistant.components.meteoclimatic pymeteoclimatic==0.1.0 +# homeassistant.components.assist_pipeline +pymicro-vad==1.0.1 + # homeassistant.components.miele pymiele==0.6.1 @@ -1885,7 +1890,7 @@ pynecil==4.2.1 pynetgear==0.10.10 # homeassistant.components.nina -pynina==0.3.6 +pynina==1.0.2 # homeassistant.components.nintendo_parental_controls pynintendoauth==1.0.2 @@ -1962,7 +1967,7 @@ pyplaato==0.0.19 pypoint==3.0.0 # homeassistant.components.portainer -pyportainer==1.0.22 +pyportainer==1.0.23 # homeassistant.components.probe_plus pyprobeplus==1.1.2 @@ -2007,7 +2012,7 @@ pyrympro==0.0.9 pysabnzbd==1.1.1 # homeassistant.components.saunum -pysaunum==0.1.0 +pysaunum==0.3.0 # homeassistant.components.schlage pyschlage==2025.9.0 @@ -2034,9 +2039,6 @@ pysiaalarm==3.1.1 # homeassistant.components.signal_messenger pysignalclirestapi==0.3.24 -# homeassistant.components.assist_pipeline -pysilero-vad==3.1.0 - # homeassistant.components.sma pysma==1.1.0 @@ -2098,7 +2100,7 @@ python-MotionMount==2.3.0 python-awair==0.2.5 # homeassistant.components.bsblan -python-bsblan==3.1.6 +python-bsblan==4.1.0 # homeassistant.components.ecobee python-ecobee-api==0.3.2 @@ -2116,7 +2118,7 @@ python-google-weather-api==0.0.4 python-homeassistant-analytics==0.9.0 # homeassistant.components.homewizard -python-homewizard-energy==10.0.0 +python-homewizard-energy==10.0.1 # homeassistant.components.izone python-izone==1.2.9 @@ -2165,7 +2167,7 @@ python-overseerr==0.8.0 python-picnic-api2==1.3.1 # homeassistant.components.pooldose -python-pooldose==0.8.1 +python-pooldose==0.8.2 # homeassistant.components.rabbitair python-rabbitair==0.0.8 @@ -2183,7 +2185,7 @@ python-snoo==0.8.3 python-songpal==0.16.2 # homeassistant.components.tado -python-tado==0.18.15 +python-tado==0.18.16 # homeassistant.components.technove python-technove==2.0.0 @@ -2277,7 +2279,7 @@ qbittorrent-api==2024.9.67 qbusmqttapi==1.4.2 # homeassistant.components.qingping -qingping-ble==1.0.1 +qingping-ble==1.1.0 # homeassistant.components.qnap qnapstats==0.4.0 @@ -2477,7 +2479,7 @@ subarulink==0.7.15 surepy==0.9.0 # homeassistant.components.switchbot_cloud -switchbot-api==2.9.0 +switchbot-api==2.10.0 # homeassistant.components.system_bridge systembridgeconnector==5.3.1 @@ -2497,7 +2499,7 @@ temperusb==1.6.1 # homeassistant.components.tesla_fleet # homeassistant.components.teslemetry # homeassistant.components.tessie -tesla-fleet-api==1.3.2 +tesla-fleet-api==1.4.2 # homeassistant.components.powerwall tesla-powerwall==0.5.2 @@ -2575,7 +2577,7 @@ typedmonarchmoney==0.4.4 uasiren==0.0.1 # homeassistant.components.unifiprotect -uiprotect==8.0.0 +uiprotect==10.0.0 # homeassistant.components.landisgyr_heat_meter ultraheat-api==0.5.7 @@ -2604,7 +2606,7 @@ uvcclient==0.12.1 vacuum-map-parser-roborock==0.1.4 # homeassistant.components.vallox -vallox-websocket-api==5.3.0 +vallox-websocket-api==6.0.0 # homeassistant.components.vegehub vegehub==0.1.26 @@ -2634,7 +2636,7 @@ visionpluspython==1.0.2 vobject==0.9.9 # homeassistant.components.voip -voip-utils==0.3.4 +voip-utils==0.3.5 # homeassistant.components.volvo volvocarsapi==0.4.3 @@ -2689,10 +2691,10 @@ wsdot==0.0.1 wyoming==1.7.2 # homeassistant.components.xiaomi_ble -xiaomi-ble==1.4.1 +xiaomi-ble==1.5.0 # homeassistant.components.knx -xknx==3.13.0 +xknx==3.14.0 # homeassistant.components.knx xknxproject==3.8.2 @@ -2747,7 +2749,7 @@ zeversolar==0.3.2 zha==0.0.84 # homeassistant.components.zwave_js -zwave-js-server-python==0.67.1 +zwave-js-server-python==0.68.0 # homeassistant.components.zwave_me zwave-me-ws==0.4.3 diff --git a/script/hassfest/manifest.py b/script/hassfest/manifest.py index 05f89f250f6..de53164aed0 100644 --- a/script/hassfest/manifest.py +++ b/script/hassfest/manifest.py @@ -427,7 +427,7 @@ def validate(integrations: dict[str, Integration], config: Config) -> None: if config.action == "generate" and manifests_resorted: subprocess.run( [ - "pre-commit", + "prek", "run", "--hook-stage", "manual", diff --git a/script/hassfest/quality_scale.py b/script/hassfest/quality_scale.py index f6d6020864e..bc97db995f3 100644 --- a/script/hassfest/quality_scale.py +++ b/script/hassfest/quality_scale.py @@ -1390,7 +1390,6 @@ INTEGRATIONS_WITHOUT_SCALE = [ "freebox", "freedns", "freedompro", - "fritz", "fritzbox", "fritzbox_callmonitor", "frontier_silicon", @@ -2000,7 +1999,6 @@ INTEGRATIONS_WITHOUT_SCALE = [ "touchline", "touchline_sl", "tplink_lte", - "tplink_omada", "traccar", "traccar_server", "tractive", diff --git a/script/hassfest/requirements.py b/script/hassfest/requirements.py index f13654d751c..ee02896b6f0 100644 --- a/script/hassfest/requirements.py +++ b/script/hassfest/requirements.py @@ -224,6 +224,11 @@ FORBIDDEN_PACKAGE_EXCEPTIONS: dict[str, dict[str, set[str]]] = { "sense": {"sense-energy": {"async-timeout"}}, "slimproto": {"aioslimproto": {"async-timeout"}}, "surepetcare": {"surepy": {"async-timeout"}}, + "tami4": { + # https://github.com/SeleniumHQ/selenium/issues/16943 + # tami4 > selenium > types* + "selenium": {"types-certifi", "types-urllib3"}, + }, "travisci": { # https://github.com/menegazzo/travispy seems to be unmaintained # and unused https://www.home-assistant.io/integrations/travisci diff --git a/script/hassfest/translations.py b/script/hassfest/translations.py index 5f73fc32e59..7c578a5e6d8 100644 --- a/script/hassfest/translations.py +++ b/script/hassfest/translations.py @@ -214,6 +214,10 @@ def gen_data_entry_schema( vol.Required("user"): translation_value_validator, str: translation_value_validator, } + else: + schema[vol.Optional("initiate_flow")] = { + vol.Required("user"): translation_value_validator, + } if flow_title == REQUIRED: schema[vol.Required("title")] = translation_value_validator elif flow_title == REMOVED: diff --git a/script/lint b/script/lint index 26b6db705f1..5a7e9314b59 100755 --- a/script/lint +++ b/script/lint @@ -15,7 +15,7 @@ printf "%s\n" $files echo "==============" echo "LINT with ruff" echo "==============" -pre-commit run ruff-check --files $files +prek run ruff-check --files $files echo "================" echo "LINT with pylint" echo "================" diff --git a/script/lint_and_test.py b/script/lint_and_test.py index 44d9e5d8eb7..ed485f4b1ed 100755 --- a/script/lint_and_test.py +++ b/script/lint_and_test.py @@ -119,7 +119,7 @@ async def pylint(files): async def ruff(files): """Exec ruff.""" - _, log = await async_exec("pre-commit", "run", "ruff", "--files", *files) + _, log = await async_exec("prek", "run", "ruff", "--files", *files) res = [] for line in log.splitlines(): line = line.split(":") diff --git a/script/scaffold/gather_info.py b/script/scaffold/gather_info.py index d90e01c3ebd..c9264aa660f 100644 --- a/script/scaffold/gather_info.py +++ b/script/scaffold/gather_info.py @@ -24,7 +24,12 @@ def gather_info(arguments) -> Info: info = _gather_info( { "domain": { - "prompt": "What is the domain?", + "prompt": ( + """What is the domain? + +Hint: The domain is a short name consisting of characters and underscores. +This domain has to be unique, cannot be changed, and has to match the directory name of the integration.""" + ), "validators": [ CHECK_EMPTY, [ @@ -72,13 +77,8 @@ def gather_new_integration(determine_auth: bool) -> Info: }, "codeowner": { "prompt": "What is your GitHub handle?", - "validators": [ - CHECK_EMPTY, - [ - 'GitHub handles need to start with an "@"', - lambda value: value.startswith("@"), - ], - ], + "validators": [CHECK_EMPTY], + "converter": lambda value: value if value.startswith("@") else f"@{value}", }, "requirement": { "prompt": "What PyPI package and version do you depend on? Leave blank for none.", diff --git a/script/setup b/script/setup index 1fd61aa9b71..9b8984f4997 100755 --- a/script/setup +++ b/script/setup @@ -31,7 +31,7 @@ fi script/bootstrap -pre-commit install +prek install hass --script ensure_config -c config diff --git a/script/version_bump.py b/script/version_bump.py index 2a7d82937f1..91571bad169 100755 --- a/script/version_bump.py +++ b/script/version_bump.py @@ -2,15 +2,19 @@ """Helper script to bump the current version.""" import argparse +from copy import replace from pathlib import Path import re import subprocess +import packaging from packaging.version import Version from homeassistant import const from homeassistant.util import dt as dt_util +_PACKAGING_VERSION_BELOW_26 = Version(packaging.__version__) < Version("26.0dev0") + def _bump_release(release, bump_type): """Bump a release tuple consisting of 3 numbers.""" @@ -25,6 +29,13 @@ def _bump_release(release, bump_type): return major, minor, patch +def _get_dev_change(dev: int) -> int | tuple[str, int]: + """Return the dev change based on packaging version.""" + if _PACKAGING_VERSION_BELOW_26: + return ("dev", dev) + return dev + + def bump_version( version: Version, bump_type: str, *, nightly_version: str | None = None ) -> Version: @@ -58,9 +69,10 @@ def bump_version( # Convert 0.67.3.b5 to 0.67.4.dev0 # Convert 0.67.3.dev0 to 0.67.3.dev1 if version.is_devrelease: - to_change["dev"] = ("dev", version.dev + 1) + to_change["dev"] = _get_dev_change(version.dev + 1) else: - to_change["pre"] = ("dev", 0) + to_change["dev"] = _get_dev_change(0) + to_change["pre"] = None to_change["release"] = _bump_release(version.release, "minor") elif bump_type == "beta": @@ -99,14 +111,19 @@ def bump_version( raise ValueError("Nightly version must be a dev version") new_dev = new_version.dev - to_change["dev"] = ("dev", new_dev) + if not isinstance(new_dev, int): + new_dev = int(new_dev) + to_change["dev"] = _get_dev_change(new_dev) else: raise ValueError(f"Unsupported type: {bump_type}") - temp = Version("0") - temp._version = version._version._replace(**to_change) # noqa: SLF001 - return Version(str(temp)) + if _PACKAGING_VERSION_BELOW_26: + temp = Version("0") + temp._version = version._version._replace(**to_change) # noqa: SLF001 + return Version(str(temp)) + + return replace(version, **to_change) def write_version(version): diff --git a/tests/common.py b/tests/common.py index dbef36f4672..efda5a6a1c3 100644 --- a/tests/common.py +++ b/tests/common.py @@ -697,6 +697,7 @@ class RegistryEntryWithDefaults(er.RegistryEntry): converter=attr.converters.default_if_none(factory=uuid_util.random_uuid_hex), # type: ignore[misc] ) has_entity_name: bool = attr.ib(default=False) + object_id_base: str | None = attr.ib(default=None) options: er.ReadOnlyEntityOptionsType = attr.ib( default=None, converter=er._protect_entity_options ) diff --git a/tests/components/__init__.py b/tests/components/__init__.py index 8c251b7d27b..6eb902d391a 100644 --- a/tests/components/__init__.py +++ b/tests/components/__init__.py @@ -5,6 +5,8 @@ from enum import StrEnum import itertools from typing import Any, TypedDict +import pytest + from homeassistant.const import ( ATTR_AREA_ID, ATTR_DEVICE_ID, @@ -12,6 +14,7 @@ from homeassistant.const import ( ATTR_LABEL_ID, CONF_ABOVE, CONF_BELOW, + CONF_CONDITION, CONF_ENTITY_ID, CONF_OPTIONS, CONF_PLATFORM, @@ -27,6 +30,10 @@ from homeassistant.helpers import ( floor_registry as fr, label_registry as lr, ) +from homeassistant.helpers.condition import ( + ConditionCheckerTypeOptional, + async_from_config as async_condition_from_config, +) from homeassistant.helpers.trigger import ( CONF_LOWER_LIMIT, CONF_THRESHOLD_TYPE, @@ -93,6 +100,13 @@ async def target_entities( suggested_object_id=f"device_{domain}", device_id=device.id, ) + entity_reg.async_get_or_create( + domain=domain, + platform="test", + unique_id=f"{domain}_device2", + suggested_object_id=f"device2_{domain}", + device_id=device.id, + ) entity_reg.async_get_or_create( domain=domain, platform="test", @@ -123,9 +137,11 @@ async def target_entities( return { "included": [ f"{domain}.standalone_{domain}", + f"{domain}.standalone2_{domain}", f"{domain}.label_{domain}", f"{domain}.area_{domain}", f"{domain}.device_{domain}", + f"{domain}.device2_{domain}", ], "excluded": [ f"{domain}.standalone_{domain}_excluded", @@ -143,33 +159,194 @@ def parametrize_target_entities(domain: str) -> list[tuple[dict, str, int]]: """ return [ ( - {CONF_ENTITY_ID: f"{domain}.standalone_{domain}"}, + { + CONF_ENTITY_ID: [ + f"{domain}.standalone_{domain}", + f"{domain}.standalone2_{domain}", + ] + }, f"{domain}.standalone_{domain}", - 1, + 2, ), - ({ATTR_LABEL_ID: "test_label"}, f"{domain}.label_{domain}", 2), - ({ATTR_AREA_ID: "test_area"}, f"{domain}.area_{domain}", 2), - ({ATTR_FLOOR_ID: "test_floor"}, f"{domain}.area_{domain}", 2), - ({ATTR_LABEL_ID: "test_label"}, f"{domain}.device_{domain}", 2), - ({ATTR_AREA_ID: "test_area"}, f"{domain}.device_{domain}", 2), - ({ATTR_FLOOR_ID: "test_floor"}, f"{domain}.device_{domain}", 2), - ({ATTR_DEVICE_ID: "test_device"}, f"{domain}.device_{domain}", 1), + ({ATTR_LABEL_ID: "test_label"}, f"{domain}.label_{domain}", 3), + ({ATTR_AREA_ID: "test_area"}, f"{domain}.area_{domain}", 3), + ({ATTR_FLOOR_ID: "test_floor"}, f"{domain}.area_{domain}", 3), + ({ATTR_LABEL_ID: "test_label"}, f"{domain}.device_{domain}", 3), + ({ATTR_AREA_ID: "test_area"}, f"{domain}.device_{domain}", 3), + ({ATTR_FLOOR_ID: "test_floor"}, f"{domain}.device_{domain}", 3), + ({ATTR_DEVICE_ID: "test_device"}, f"{domain}.device_{domain}", 2), ] class _StateDescription(TypedDict): - """Test state and expected service call count.""" + """Test state with attributes.""" state: str | None attributes: dict -class StateDescription(TypedDict): +class TriggerStateDescription(TypedDict): """Test state and expected service call count.""" - included: _StateDescription - excluded: _StateDescription - count: int + included: _StateDescription # State for entities meant to be targeted + excluded: _StateDescription # State for entities not meant to be targeted + count: int # Expected service call count + + +class ConditionStateDescription(TypedDict): + """Test state and expected condition evaluation.""" + + included: _StateDescription # State for entities meant to be targeted + excluded: _StateDescription # State for entities not meant to be targeted + + condition_true: bool # If the condition is expected to evaluate to true + condition_true_first_entity: bool # If the condition is expected to evaluate to true for the first targeted entity + + +def _parametrize_condition_states( + *, + condition: str, + condition_options: dict[str, Any] | None = None, + target_states: list[str | None | tuple[str | None, dict]], + other_states: list[str | None | tuple[str | None, dict]], + additional_attributes: dict | None, + condition_true_if_invalid: bool, +) -> list[tuple[str, dict[str, Any], list[ConditionStateDescription]]]: + """Parametrize states and expected condition evaluations. + + The target_states and other_states iterables are either iterables of + states or iterables of (state, attributes) tuples. + + Returns a list of tuples with (condition, condition options, list of states), + where states is a list of ConditionStateDescription dicts. + """ + + additional_attributes = additional_attributes or {} + condition_options = condition_options or {} + + def state_with_attributes( + state: str | None | tuple[str | None, dict], + condition_true: bool, + condition_true_first_entity: bool, + ) -> ConditionStateDescription: + """Return ConditionStateDescription dict.""" + if isinstance(state, str) or state is None: + return { + "included": { + "state": state, + "attributes": additional_attributes, + }, + "excluded": { + "state": state, + "attributes": {}, + }, + "condition_true": condition_true, + "condition_true_first_entity": condition_true_first_entity, + } + return { + "included": { + "state": state[0], + "attributes": state[1] | additional_attributes, + }, + "excluded": { + "state": state[0], + "attributes": state[1], + }, + "condition_true": condition_true, + "condition_true_first_entity": condition_true_first_entity, + } + + return [ + ( + condition, + condition_options, + list( + itertools.chain( + (state_with_attributes(None, condition_true_if_invalid, True),), + ( + state_with_attributes( + STATE_UNAVAILABLE, condition_true_if_invalid, True + ), + ), + ( + state_with_attributes( + STATE_UNKNOWN, condition_true_if_invalid, True + ), + ), + ( + state_with_attributes(other_state, False, False) + for other_state in other_states + ), + ), + ), + ), + # Test each target state individually to isolate condition_true expectations + *( + ( + condition, + condition_options, + [ + state_with_attributes(other_states[0], False, False), + state_with_attributes(target_state, True, False), + ], + ) + for target_state in target_states + ), + ] + + +def parametrize_condition_states_any( + *, + condition: str, + condition_options: dict[str, Any] | None = None, + target_states: list[str | None | tuple[str | None, dict]], + other_states: list[str | None | tuple[str | None, dict]], + additional_attributes: dict | None = None, +) -> list[tuple[str, dict[str, Any], list[ConditionStateDescription]]]: + """Parametrize states and expected condition evaluations. + + The target_states and other_states iterables are either iterables of + states or iterables of (state, attributes) tuples. + + Returns a list of tuples with (condition, condition options, list of states), + where states is a list of ConditionStateDescription dicts. + """ + + return _parametrize_condition_states( + condition=condition, + condition_options=condition_options, + target_states=target_states, + other_states=other_states, + additional_attributes=additional_attributes, + condition_true_if_invalid=False, + ) + + +def parametrize_condition_states_all( + *, + condition: str, + condition_options: dict[str, Any] | None = None, + target_states: list[str | None | tuple[str | None, dict]], + other_states: list[str | None | tuple[str | None, dict]], + additional_attributes: dict | None = None, +) -> list[tuple[str, dict[str, Any], list[ConditionStateDescription]]]: + """Parametrize states and expected condition evaluations. + + The target_states and other_states iterables are either iterables of + states or iterables of (state, attributes) tuples. + + Returns a list of tuples with (condition, condition options, list of states), + where states is a list of ConditionStateDescription dicts. + """ + + return _parametrize_condition_states( + condition=condition, + condition_options=condition_options, + target_states=target_states, + other_states=other_states, + additional_attributes=additional_attributes, + condition_true_if_invalid=True, + ) def parametrize_trigger_states( @@ -181,7 +358,7 @@ def parametrize_trigger_states( additional_attributes: dict | None = None, trigger_from_none: bool = True, retrigger_on_target_state: bool = False, -) -> list[tuple[str, dict[str, Any], list[StateDescription]]]: +) -> list[tuple[str, dict[str, Any], list[TriggerStateDescription]]]: """Parametrize states and expected service call counts. The target_states and other_states iterables are either iterables of @@ -194,7 +371,7 @@ def parametrize_trigger_states( when the state changes to another target state. Returns a list of tuples with (trigger, list of states), - where states is a list of StateDescription dicts. + where states is a list of TriggerStateDescription dicts. """ additional_attributes = additional_attributes or {} @@ -202,8 +379,8 @@ def parametrize_trigger_states( def state_with_attributes( state: str | None | tuple[str | None, dict], count: int - ) -> dict: - """Return (state, attributes) dict.""" + ) -> TriggerStateDescription: + """Return TriggerStateDescription dict.""" if isinstance(state, str) or state is None: return { "included": { @@ -353,7 +530,7 @@ def parametrize_trigger_states( def parametrize_numerical_attribute_changed_trigger_states( trigger: str, state: str, attribute: str -) -> list[tuple[str, dict[str, Any], list[StateDescription]]]: +) -> list[tuple[str, dict[str, Any], list[TriggerStateDescription]]]: """Parametrize states and expected service call counts for numerical changed triggers.""" return [ *parametrize_trigger_states( @@ -398,7 +575,7 @@ def parametrize_numerical_attribute_changed_trigger_states( def parametrize_numerical_attribute_crossed_threshold_trigger_states( trigger: str, state: str, attribute: str -) -> list[tuple[str, dict[str, Any], list[StateDescription]]]: +) -> list[tuple[str, dict[str, Any], list[TriggerStateDescription]]]: """Parametrize states and expected service call counts for numerical crossed threshold triggers.""" return [ *parametrize_trigger_states( @@ -500,10 +677,28 @@ async def arm_trigger( ) +async def create_target_condition( + hass: HomeAssistant, + *, + condition: str, + target: dict, + behavior: str, +) -> ConditionCheckerTypeOptional: + """Create a target condition.""" + return await async_condition_from_config( + hass, + { + CONF_CONDITION: condition, + CONF_TARGET: target, + CONF_OPTIONS: {"behavior": behavior}, + }, + ) + + def set_or_remove_state( hass: HomeAssistant, entity_id: str, - state: StateDescription, + state: TriggerStateDescription, ) -> None: """Set or remove the state of an entity.""" if state["state"] is None: @@ -526,3 +721,37 @@ def other_states(state: StrEnum | Iterable[StrEnum]) -> list[str]: enum_class = list(state)[0].__class__ return sorted({s.value for s in enum_class} - excluded_values) + + +async def assert_condition_gated_by_labs_flag( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str +) -> None: + """Helper to check that a condition is gated by the labs flag.""" + + # Local include to avoid importing the automation component unnecessarily + from homeassistant.components import automation # noqa: PLC0415 + + await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: { + "trigger": {"platform": "event", "event_type": "test_event"}, + "condition": { + CONF_CONDITION: condition, + CONF_TARGET: {ATTR_LABEL_ID: "test_label"}, + CONF_OPTIONS: {"behavior": "any"}, + }, + "action": { + "service": "test.automation", + }, + } + }, + ) + + assert ( + "Unnamed automation failed to setup conditions and has been disabled: " + f"Condition '{condition}' requires the experimental 'New triggers and " + "conditions' feature to be enabled in Home Assistant Labs settings " + "(feature flag: 'new_triggers_conditions')" + ) in caplog.text diff --git a/tests/components/acaia/snapshots/test_binary_sensor.ambr b/tests/components/acaia/snapshots/test_binary_sensor.ambr index 3ebf6fb128f..9967d21392f 100644 --- a/tests/components/acaia/snapshots/test_binary_sensor.ambr +++ b/tests/components/acaia/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Timer running', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/acaia/snapshots/test_button.ambr b/tests/components/acaia/snapshots/test_button.ambr index 4caea489ef0..7e8c0d5da01 100644 --- a/tests/components/acaia/snapshots/test_button.ambr +++ b/tests/components/acaia/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset timer', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start/stop timer', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tare', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/acaia/snapshots/test_sensor.ambr b/tests/components/acaia/snapshots/test_sensor.ambr index 811485a64ee..e0c7a4c1abd 100644 --- a/tests/components/acaia/snapshots/test_sensor.ambr +++ b/tests/components/acaia/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume flow rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weight', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/accuweather/snapshots/test_sensor.ambr b/tests/components/accuweather/snapshots/test_sensor.ambr index 67337d4d0e4..64abcac7e74 100644 --- a/tests/components/accuweather/snapshots/test_sensor.ambr +++ b/tests/components/accuweather/snapshots/test_sensor.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality day 0', 'options': dict({ }), 'original_device_class': , @@ -93,6 +94,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality day 1', 'options': dict({ }), 'original_device_class': , @@ -158,6 +160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality day 2', 'options': dict({ }), 'original_device_class': , @@ -223,6 +226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality day 3', 'options': dict({ }), 'original_device_class': , @@ -288,6 +292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality day 4', 'options': dict({ }), 'original_device_class': , @@ -347,6 +352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -404,6 +410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud ceiling', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -461,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover', 'options': dict({ }), 'original_device_class': None, @@ -512,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover day 0', 'options': dict({ }), 'original_device_class': None, @@ -562,6 +571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover day 1', 'options': dict({ }), 'original_device_class': None, @@ -612,6 +622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover day 2', 'options': dict({ }), 'original_device_class': None, @@ -662,6 +673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover day 3', 'options': dict({ }), 'original_device_class': None, @@ -712,6 +724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover day 4', 'options': dict({ }), 'original_device_class': None, @@ -762,6 +775,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover night 0', 'options': dict({ }), 'original_device_class': None, @@ -812,6 +826,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover night 1', 'options': dict({ }), 'original_device_class': None, @@ -862,6 +877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover night 2', 'options': dict({ }), 'original_device_class': None, @@ -912,6 +928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover night 3', 'options': dict({ }), 'original_device_class': None, @@ -962,6 +979,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud cover night 4', 'options': dict({ }), 'original_device_class': None, @@ -1012,6 +1030,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition day 0', 'options': dict({ }), 'original_device_class': None, @@ -1061,6 +1080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition day 1', 'options': dict({ }), 'original_device_class': None, @@ -1110,6 +1130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition day 2', 'options': dict({ }), 'original_device_class': None, @@ -1159,6 +1180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition day 3', 'options': dict({ }), 'original_device_class': None, @@ -1208,6 +1230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition day 4', 'options': dict({ }), 'original_device_class': None, @@ -1257,6 +1280,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition night 0', 'options': dict({ }), 'original_device_class': None, @@ -1306,6 +1330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition night 1', 'options': dict({ }), 'original_device_class': None, @@ -1355,6 +1380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition night 2', 'options': dict({ }), 'original_device_class': None, @@ -1404,6 +1430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition night 3', 'options': dict({ }), 'original_device_class': None, @@ -1453,6 +1480,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition night 4', 'options': dict({ }), 'original_device_class': None, @@ -1504,6 +1532,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1559,6 +1588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grass pollen day 0', 'options': dict({ }), 'original_device_class': None, @@ -1610,6 +1640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grass pollen day 1', 'options': dict({ }), 'original_device_class': None, @@ -1661,6 +1692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grass pollen day 2', 'options': dict({ }), 'original_device_class': None, @@ -1712,6 +1744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grass pollen day 3', 'options': dict({ }), 'original_device_class': None, @@ -1763,6 +1796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grass pollen day 4', 'options': dict({ }), 'original_device_class': None, @@ -1814,6 +1848,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hours of sun day 0', 'options': dict({ }), 'original_device_class': None, @@ -1864,6 +1899,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hours of sun day 1', 'options': dict({ }), 'original_device_class': None, @@ -1914,6 +1950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hours of sun day 2', 'options': dict({ }), 'original_device_class': None, @@ -1964,6 +2001,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hours of sun day 3', 'options': dict({ }), 'original_device_class': None, @@ -2014,6 +2052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hours of sun day 4', 'options': dict({ }), 'original_device_class': None, @@ -2066,6 +2105,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2118,6 +2158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mold pollen day 0', 'options': dict({ }), 'original_device_class': None, @@ -2169,6 +2210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mold pollen day 1', 'options': dict({ }), 'original_device_class': None, @@ -2220,6 +2262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mold pollen day 2', 'options': dict({ }), 'original_device_class': None, @@ -2271,6 +2314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mold pollen day 3', 'options': dict({ }), 'original_device_class': None, @@ -2322,6 +2366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mold pollen day 4', 'options': dict({ }), 'original_device_class': None, @@ -2375,6 +2420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2433,6 +2479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2494,6 +2541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure tendency', 'options': dict({ }), 'original_device_class': , @@ -2549,6 +2597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ragweed pollen day 0', 'options': dict({ }), 'original_device_class': None, @@ -2600,6 +2649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ragweed pollen day 1', 'options': dict({ }), 'original_device_class': None, @@ -2651,6 +2701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ragweed pollen day 2', 'options': dict({ }), 'original_device_class': None, @@ -2702,6 +2753,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ragweed pollen day 3', 'options': dict({ }), 'original_device_class': None, @@ -2753,6 +2805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ragweed pollen day 4', 'options': dict({ }), 'original_device_class': None, @@ -2806,6 +2859,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2861,6 +2915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature max day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2915,6 +2970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature max day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2969,6 +3025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature max day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3023,6 +3080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature max day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3077,6 +3135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature max day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3131,6 +3190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature min day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3185,6 +3245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature min day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3239,6 +3300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature min day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3293,6 +3355,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature min day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3347,6 +3410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature min day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3403,6 +3467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3458,6 +3523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade max day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3512,6 +3578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade max day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3566,6 +3633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade max day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3620,6 +3688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade max day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3674,6 +3743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade max day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3728,6 +3798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade min day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3782,6 +3853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade min day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3836,6 +3908,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade min day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3890,6 +3963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade min day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3944,6 +4018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RealFeel temperature shade min day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3998,6 +4073,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4052,6 +4128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4106,6 +4183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4160,6 +4238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4214,6 +4293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4268,6 +4348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance night 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4322,6 +4403,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance night 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4376,6 +4458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance night 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4430,6 +4513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance night 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4484,6 +4568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar irradiance night 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4540,6 +4625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4595,6 +4681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability day 0', 'options': dict({ }), 'original_device_class': None, @@ -4645,6 +4732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability day 1', 'options': dict({ }), 'original_device_class': None, @@ -4695,6 +4783,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability day 2', 'options': dict({ }), 'original_device_class': None, @@ -4745,6 +4834,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability day 3', 'options': dict({ }), 'original_device_class': None, @@ -4795,6 +4885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability day 4', 'options': dict({ }), 'original_device_class': None, @@ -4845,6 +4936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability night 0', 'options': dict({ }), 'original_device_class': None, @@ -4895,6 +4987,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability night 1', 'options': dict({ }), 'original_device_class': None, @@ -4945,6 +5038,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability night 2', 'options': dict({ }), 'original_device_class': None, @@ -4995,6 +5089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability night 3', 'options': dict({ }), 'original_device_class': None, @@ -5045,6 +5140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability night 4', 'options': dict({ }), 'original_device_class': None, @@ -5095,6 +5191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tree pollen day 0', 'options': dict({ }), 'original_device_class': None, @@ -5146,6 +5243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tree pollen day 1', 'options': dict({ }), 'original_device_class': None, @@ -5197,6 +5295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tree pollen day 2', 'options': dict({ }), 'original_device_class': None, @@ -5248,6 +5347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tree pollen day 3', 'options': dict({ }), 'original_device_class': None, @@ -5299,6 +5399,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tree pollen day 4', 'options': dict({ }), 'original_device_class': None, @@ -5352,6 +5453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -5404,6 +5506,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index day 0', 'options': dict({ }), 'original_device_class': None, @@ -5455,6 +5558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index day 1', 'options': dict({ }), 'original_device_class': None, @@ -5506,6 +5610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index day 2', 'options': dict({ }), 'original_device_class': None, @@ -5557,6 +5662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index day 3', 'options': dict({ }), 'original_device_class': None, @@ -5608,6 +5714,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index day 4', 'options': dict({ }), 'original_device_class': None, @@ -5661,6 +5768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wet bulb temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5718,6 +5826,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind chill temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5775,6 +5884,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5830,6 +5940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5885,6 +5996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5940,6 +6052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5995,6 +6108,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6050,6 +6164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6105,6 +6220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed night 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6160,6 +6276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed night 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6215,6 +6332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed night 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6270,6 +6388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed night 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6325,6 +6444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed night 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6382,6 +6502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6437,6 +6558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed day 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6492,6 +6614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed day 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6547,6 +6670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed day 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6602,6 +6726,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed day 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6657,6 +6782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed day 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6712,6 +6838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed night 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6767,6 +6894,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed night 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6822,6 +6950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed night 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6877,6 +7006,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed night 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6932,6 +7062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed night 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/accuweather/snapshots/test_weather.ambr b/tests/components/accuweather/snapshots/test_weather.ambr index ae17c76511c..80e7a67c048 100644 --- a/tests/components/accuweather/snapshots/test_weather.ambr +++ b/tests/components/accuweather/snapshots/test_weather.ambr @@ -437,6 +437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/actron_air/snapshots/test_switch.ambr b/tests/components/actron_air/snapshots/test_switch.ambr index 5735835c8ea..cafeaa6b22a 100644 --- a/tests/components/actron_air/snapshots/test_switch.ambr +++ b/tests/components/actron_air/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away mode', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Continuous fan', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quiet mode', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turbo mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/adax/snapshots/test_sensor.ambr b/tests/components/adax/snapshots/test_sensor.ambr index ecdf2364301..7d449ee9d83 100644 --- a/tests/components/adax/snapshots/test_sensor.ambr +++ b/tests/components/adax/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -137,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -252,6 +256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -311,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -367,6 +373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -426,6 +433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/adguard/snapshots/test_sensor.ambr b/tests/components/adguard/snapshots/test_sensor.ambr index df161bf7d39..dcbed0dce78 100644 --- a/tests/components/adguard/snapshots/test_sensor.ambr +++ b/tests/components/adguard/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average processing speed', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries blocked', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries blocked ratio', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Parental control blocked', 'options': dict({ }), 'original_device_class': None, @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rules count', 'options': dict({ }), 'original_device_class': None, @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safe browsing blocked', 'options': dict({ }), 'original_device_class': None, @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safe searches enforced', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/adguard/snapshots/test_switch.ambr b/tests/components/adguard/snapshots/test_switch.ambr index b98165d7653..2eab04afd49 100644 --- a/tests/components/adguard/snapshots/test_switch.ambr +++ b/tests/components/adguard/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filtering', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Parental control', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Protection', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Query log', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safe browsing', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safe search', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/adguard/snapshots/test_update.ambr b/tests/components/adguard/snapshots/test_update.ambr index fc6af1b61ee..e25ed5106aa 100644 --- a/tests/components/adguard/snapshots/test_update.ambr +++ b/tests/components/adguard/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airgradient/snapshots/test_button.ambr b/tests/components/airgradient/snapshots/test_button.ambr index ca4c55230d2..d690837b861 100644 --- a/tests/components/airgradient/snapshots/test_button.ambr +++ b/tests/components/airgradient/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibrate CO2 sensor', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test LED bar', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibrate CO2 sensor', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airgradient/snapshots/test_number.ambr b/tests/components/airgradient/snapshots/test_number.ambr index 4440f4353a1..c77673680b2 100644 --- a/tests/components/airgradient/snapshots/test_number.ambr +++ b/tests/components/airgradient/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display brightness', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED bar brightness', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airgradient/snapshots/test_select.ambr b/tests/components/airgradient/snapshots/test_select.ambr index f282d27bc61..79ca2ee76eb 100644 --- a/tests/components/airgradient/snapshots/test_select.ambr +++ b/tests/components/airgradient/snapshots/test_select.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CO2 automatic baseline duration', 'options': dict({ }), 'original_device_class': None, @@ -90,6 +91,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration source', 'options': dict({ }), 'original_device_class': None, @@ -147,6 +149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display PM standard', 'options': dict({ }), 'original_device_class': None, @@ -204,6 +207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display temperature unit', 'options': dict({ }), 'original_device_class': None, @@ -262,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED bar mode', 'options': dict({ }), 'original_device_class': None, @@ -323,6 +328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index learning offset', 'options': dict({ }), 'original_device_class': None, @@ -386,6 +392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index learning offset', 'options': dict({ }), 'original_device_class': None, @@ -450,6 +457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CO2 automatic baseline duration', 'options': dict({ }), 'original_device_class': None, @@ -511,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration source', 'options': dict({ }), 'original_device_class': None, @@ -571,6 +580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index learning offset', 'options': dict({ }), 'original_device_class': None, @@ -634,6 +644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index learning offset', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airgradient/snapshots/test_sensor.ambr b/tests/components/airgradient/snapshots/test_sensor.ambr index e205e626ab8..e8f8a289aec 100644 --- a/tests/components/airgradient/snapshots/test_sensor.ambr +++ b/tests/components/airgradient/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide automatic baseline calibration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display brightness', 'options': dict({ }), 'original_device_class': None, @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display PM standard', 'options': dict({ }), 'original_device_class': , @@ -238,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display temperature unit', 'options': dict({ }), 'original_device_class': , @@ -293,6 +298,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -344,6 +350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED bar brightness', 'options': dict({ }), 'original_device_class': None, @@ -399,6 +406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED bar mode', 'options': dict({ }), 'original_device_class': , @@ -455,6 +463,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index', 'options': dict({ }), 'original_device_class': None, @@ -504,6 +513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index learning offset', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -559,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM0.3', 'options': dict({ }), 'original_device_class': None, @@ -611,6 +622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -664,6 +676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -717,6 +730,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -770,6 +784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw NOx', 'options': dict({ }), 'original_device_class': None, @@ -822,6 +837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw PM2.5', 'options': dict({ }), 'original_device_class': , @@ -875,6 +891,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw VOC', 'options': dict({ }), 'original_device_class': None, @@ -927,6 +944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -980,6 +998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1036,6 +1055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index', 'options': dict({ }), 'original_device_class': None, @@ -1085,6 +1105,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index learning offset', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1138,6 +1159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide automatic baseline calibration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1193,6 +1215,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index', 'options': dict({ }), 'original_device_class': None, @@ -1242,6 +1265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index learning offset', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1297,6 +1321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw NOx', 'options': dict({ }), 'original_device_class': None, @@ -1349,6 +1374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw VOC', 'options': dict({ }), 'original_device_class': None, @@ -1401,6 +1427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1454,6 +1481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index', 'options': dict({ }), 'original_device_class': None, @@ -1503,6 +1531,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index learning offset', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/airgradient/snapshots/test_switch.ambr b/tests/components/airgradient/snapshots/test_switch.ambr index f39654d66a7..45b1d26a4b5 100644 --- a/tests/components/airgradient/snapshots/test_switch.ambr +++ b/tests/components/airgradient/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Post data to Airgradient', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airgradient/snapshots/test_update.ambr b/tests/components/airgradient/snapshots/test_update.ambr index cf8ccec28dd..891ed4e25ac 100644 --- a/tests/components/airgradient/snapshots/test_update.ambr +++ b/tests/components/airgradient/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/airly/snapshots/test_sensor.ambr b/tests/components/airly/snapshots/test_sensor.ambr index 8d79f8cdf0a..ea33cdcc0a3 100644 --- a/tests/components/airly/snapshots/test_sensor.ambr +++ b/tests/components/airly/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Common air quality index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -136,6 +138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -252,6 +256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -311,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -368,6 +374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -427,6 +434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -486,6 +494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -543,6 +552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sulphur dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -602,6 +612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/airobot/snapshots/test_button.ambr b/tests/components/airobot/snapshots/test_button.ambr index d378d5c6e24..14977c59c6e 100644 --- a/tests/components/airobot/snapshots/test_button.ambr +++ b/tests/components/airobot/snapshots/test_button.ambr @@ -1,4 +1,53 @@ # serializer version: 1 +# name: test_buttons[button.test_thermostat_recalibrate_co2_sensor-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.test_thermostat_recalibrate_co2_sensor', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Recalibrate CO2 sensor', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Recalibrate CO2 sensor', + 'platform': 'airobot', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'recalibrate_co2', + 'unique_id': 'T01A1B2C3_recalibrate_co2', + 'unit_of_measurement': None, + }) +# --- +# name: test_buttons[button.test_thermostat_recalibrate_co2_sensor-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Test Thermostat Recalibrate CO2 sensor', + }), + 'context': , + 'entity_id': 'button.test_thermostat_recalibrate_co2_sensor', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_buttons[button.test_thermostat_restart-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -20,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/airobot/snapshots/test_climate.ambr b/tests/components/airobot/snapshots/test_climate.ambr index 4dfc2588ed5..4fa0c5611e5 100644 --- a/tests/components/airobot/snapshots/test_climate.ambr +++ b/tests/components/airobot/snapshots/test_climate.ambr @@ -31,6 +31,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airobot/snapshots/test_number.ambr b/tests/components/airobot/snapshots/test_number.ambr index e98999a1563..8afa9c59ad3 100644 --- a/tests/components/airobot/snapshots/test_number.ambr +++ b/tests/components/airobot/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hysteresis band', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/airobot/snapshots/test_sensor.ambr b/tests/components/airobot/snapshots/test_sensor.ambr index 91e56125332..860c488ed60 100644 --- a/tests/components/airobot/snapshots/test_sensor.ambr +++ b/tests/components/airobot/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device uptime', 'options': dict({ }), 'original_device_class': , @@ -127,6 +129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error count', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating uptime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -237,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/airobot/snapshots/test_switch.ambr b/tests/components/airobot/snapshots/test_switch.ambr new file mode 100644 index 00000000000..6d7d816085c --- /dev/null +++ b/tests/components/airobot/snapshots/test_switch.ambr @@ -0,0 +1,99 @@ +# serializer version: 1 +# name: test_switches[switch.test_thermostat_actuator_exercise_disabled-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.test_thermostat_actuator_exercise_disabled', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Actuator exercise disabled', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Actuator exercise disabled', + 'platform': 'airobot', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'actuator_exercise_disabled', + 'unique_id': 'T01A1B2C3_actuator_exercise_disabled', + 'unit_of_measurement': None, + }) +# --- +# name: test_switches[switch.test_thermostat_actuator_exercise_disabled-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Test Thermostat Actuator exercise disabled', + }), + 'context': , + 'entity_id': 'switch.test_thermostat_actuator_exercise_disabled', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_switches[switch.test_thermostat_child_lock-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.test_thermostat_child_lock', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Child lock', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Child lock', + 'platform': 'airobot', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'child_lock', + 'unique_id': 'T01A1B2C3_child_lock', + 'unit_of_measurement': None, + }) +# --- +# name: test_switches[switch.test_thermostat_child_lock-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Test Thermostat Child lock', + }), + 'context': , + 'entity_id': 'switch.test_thermostat_child_lock', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/airobot/test_button.py b/tests/components/airobot/test_button.py index 60ddb2e8e96..529605836a9 100644 --- a/tests/components/airobot/test_button.py +++ b/tests/components/airobot/test_button.py @@ -25,7 +25,7 @@ def platforms() -> list[Platform]: return [Platform.BUTTON] -@pytest.mark.usefixtures("init_integration") +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") async def test_buttons( hass: HomeAssistant, snapshot: SnapshotAssertion, @@ -93,3 +93,38 @@ async def test_restart_button_connection_errors( ) mock_airobot_client.reboot_thermostat.assert_called_once() + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +async def test_recalibrate_co2_button( + hass: HomeAssistant, + mock_airobot_client: AsyncMock, +) -> None: + """Test recalibrate CO2 sensor button.""" + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.test_thermostat_recalibrate_co2_sensor"}, + blocking=True, + ) + + mock_airobot_client.recalibrate_co2_sensor.assert_called_once() + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +async def test_recalibrate_co2_button_error( + hass: HomeAssistant, + mock_airobot_client: AsyncMock, +) -> None: + """Test recalibrate CO2 sensor button error handling.""" + mock_airobot_client.recalibrate_co2_sensor.side_effect = AirobotError("Test error") + + with pytest.raises(HomeAssistantError): + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.test_thermostat_recalibrate_co2_sensor"}, + blocking=True, + ) + + mock_airobot_client.recalibrate_co2_sensor.assert_called_once() diff --git a/tests/components/airobot/test_switch.py b/tests/components/airobot/test_switch.py new file mode 100644 index 00000000000..1cf52202011 --- /dev/null +++ b/tests/components/airobot/test_switch.py @@ -0,0 +1,177 @@ +"""Tests for the Airobot switch platform.""" + +from unittest.mock import AsyncMock + +from pyairobotrest.exceptions import AirobotError +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_OFF, + STATE_ON, + Platform, +) +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import entity_registry as er + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.fixture +def platforms() -> list[Platform]: + """Fixture to specify platforms to test.""" + return [Platform.SWITCH] + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +async def test_switches( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test the switch entities.""" + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +@pytest.mark.parametrize( + ("entity_id", "method_name"), + [ + ("switch.test_thermostat_child_lock", "set_child_lock"), + ( + "switch.test_thermostat_actuator_exercise_disabled", + "toggle_actuator_exercise", + ), + ], +) +async def test_switch_turn_on_off( + hass: HomeAssistant, + mock_airobot_client: AsyncMock, + entity_id: str, + method_name: str, +) -> None: + """Test switch turn on/off functionality.""" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_OFF + + mock_method = getattr(mock_airobot_client, method_name) + + # Turn on + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + mock_method.assert_called_once_with(True) + mock_method.reset_mock() + + # Turn off + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + mock_method.assert_called_once_with(False) + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +async def test_switch_state_updates( + hass: HomeAssistant, + mock_airobot_client: AsyncMock, + mock_settings, + mock_config_entry: MockConfigEntry, +) -> None: + """Test that switch state updates when coordinator refreshes.""" + # Initial state - both switches off + child_lock = hass.states.get("switch.test_thermostat_child_lock") + assert child_lock is not None + assert child_lock.state == STATE_OFF + + actuator_disabled = hass.states.get( + "switch.test_thermostat_actuator_exercise_disabled" + ) + assert actuator_disabled is not None + assert actuator_disabled.state == STATE_OFF + + # Update settings to enable both + mock_settings.setting_flags.childlock_enabled = True + mock_settings.setting_flags.actuator_exercise_disabled = True + mock_airobot_client.get_settings.return_value = mock_settings + + # Trigger coordinator update + await mock_config_entry.runtime_data.async_refresh() + await hass.async_block_till_done() + + # Verify states updated + child_lock = hass.states.get("switch.test_thermostat_child_lock") + assert child_lock is not None + assert child_lock.state == STATE_ON + + actuator_disabled = hass.states.get( + "switch.test_thermostat_actuator_exercise_disabled" + ) + assert actuator_disabled is not None + assert actuator_disabled.state == STATE_ON + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +@pytest.mark.parametrize( + ("entity_id", "method_name", "service", "expected_key"), + [ + ( + "switch.test_thermostat_child_lock", + "set_child_lock", + SERVICE_TURN_ON, + "child_lock", + ), + ( + "switch.test_thermostat_child_lock", + "set_child_lock", + SERVICE_TURN_OFF, + "child_lock", + ), + ( + "switch.test_thermostat_actuator_exercise_disabled", + "toggle_actuator_exercise", + SERVICE_TURN_ON, + "actuator_exercise_disabled", + ), + ( + "switch.test_thermostat_actuator_exercise_disabled", + "toggle_actuator_exercise", + SERVICE_TURN_OFF, + "actuator_exercise_disabled", + ), + ], +) +async def test_switch_error_handling( + hass: HomeAssistant, + mock_airobot_client: AsyncMock, + entity_id: str, + method_name: str, + service: str, + expected_key: str, +) -> None: + """Test switch error handling for turn on/off operations.""" + mock_method = getattr(mock_airobot_client, method_name) + mock_method.side_effect = AirobotError("Test error") + + with pytest.raises(HomeAssistantError, match=expected_key): + await hass.services.async_call( + SWITCH_DOMAIN, + service, + {ATTR_ENTITY_ID: entity_id}, + blocking=True, + ) + + expected_value = service == SERVICE_TURN_ON + mock_method.assert_called_once_with(expected_value) diff --git a/tests/components/airos/snapshots/test_binary_sensor.ambr b/tests/components/airos/snapshots/test_binary_sensor.ambr index 65705c7f629..e03d7e2e513 100644 --- a/tests/components/airos/snapshots/test_binary_sensor.ambr +++ b/tests/components/airos/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHCP client', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHCP server', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHCPv6 server', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port forwarding', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PPPoE link', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/airos/snapshots/test_sensor.ambr b/tests/components/airos/snapshots/test_sensor.ambr index 815b11ddc7e..1ab57de9684 100644 --- a/tests/components/airos/snapshots/test_sensor.ambr +++ b/tests/components/airos/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Antenna gain', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU load', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Download capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -192,6 +195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Network role', 'options': dict({ }), 'original_device_class': , @@ -247,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Throughput receive (actual)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -306,6 +311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Throughput transmit (actual)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -365,6 +371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upload capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -422,6 +429,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -478,6 +486,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wireless distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -536,6 +545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wireless frequency', 'options': dict({ }), 'original_device_class': , @@ -592,6 +602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wireless mode', 'options': dict({ }), 'original_device_class': , @@ -650,6 +661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wireless role', 'options': dict({ }), 'original_device_class': , @@ -703,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wireless SSID', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airpatrol/snapshots/test_climate.ambr b/tests/components/airpatrol/snapshots/test_climate.ambr index 9495481c0e8..e1257e2dd1f 100644 --- a/tests/components/airpatrol/snapshots/test_climate.ambr +++ b/tests/components/airpatrol/snapshots/test_climate.ambr @@ -37,6 +37,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -119,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/airpatrol/snapshots/test_sensor.ambr b/tests/components/airpatrol/snapshots/test_sensor.ambr index 3a142cf34f6..4047d76d9c7 100644 --- a/tests/components/airpatrol/snapshots/test_sensor.ambr +++ b/tests/components/airpatrol/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/airthings/snapshots/test_sensor.ambr b/tests/components/airthings/snapshots/test_sensor.ambr index 9cc3d1bcd13..73b33684694 100644 --- a/tests/components/airthings/snapshots/test_sensor.ambr +++ b/tests/components/airthings/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -137,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -249,6 +253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -305,6 +310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -361,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radon', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -416,6 +423,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -472,6 +480,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -528,6 +537,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -587,6 +597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -643,6 +654,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -699,6 +711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -755,6 +768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -811,6 +825,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -867,6 +882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -923,6 +939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -979,6 +996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1038,6 +1056,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1094,6 +1113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1150,6 +1170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1206,6 +1227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radon', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1261,6 +1283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1317,6 +1340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/airtouch5/snapshots/test_cover.ambr b/tests/components/airtouch5/snapshots/test_cover.ambr index 3db5075eb0f..adfc36c915e 100644 --- a/tests/components/airtouch5/snapshots/test_cover.ambr +++ b/tests/components/airtouch5/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Damper', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Damper', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/airzone/snapshots/test_sensor.ambr b/tests/components/airzone/snapshots/test_sensor.ambr index 491b6c6313b..0ab053108a5 100644 --- a/tests/components/airzone/snapshots/test_sensor.ambr +++ b/tests/components/airzone/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RSSI', 'options': dict({ }), 'original_device_class': , @@ -240,6 +244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -296,6 +301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -349,6 +355,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -402,6 +409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -454,6 +462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -510,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -566,6 +576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -619,6 +630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -672,6 +684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -724,6 +737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -780,6 +794,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -833,6 +848,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -886,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -938,6 +955,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -994,6 +1012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1047,6 +1066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1100,6 +1120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -1152,6 +1173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1208,6 +1230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1261,6 +1284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/airzone/test_select.py b/tests/components/airzone/test_select.py index 343c033728a..4421822f1c8 100644 --- a/tests/components/airzone/test_select.py +++ b/tests/components/airzone/test_select.py @@ -2,12 +2,13 @@ from unittest.mock import patch -from aioairzone.common import OperationMode +from aioairzone.common import OperationMode, QAdapt from aioairzone.const import ( API_COLD_ANGLE, API_DATA, API_HEAT_ANGLE, API_MODE, + API_Q_ADAPT, API_SLEEP, API_SYSTEM_ID, API_ZONE_ID, @@ -17,7 +18,7 @@ import pytest from homeassistant.components.select import ATTR_OPTIONS, DOMAIN as SELECT_DOMAIN from homeassistant.const import ATTR_ENTITY_ID, ATTR_OPTION, SERVICE_SELECT_OPTION from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ServiceValidationError +from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from .util import async_init_integration @@ -27,6 +28,11 @@ async def test_airzone_create_selects(hass: HomeAssistant) -> None: await async_init_integration(hass) + # Systems + state = hass.states.get("select.system_1_q_adapt") + assert state.state == "standard" + + # Zones state = hass.states.get("select.despacho_cold_angle") assert state.state == "90deg" @@ -95,6 +101,71 @@ async def test_airzone_create_selects(hass: HomeAssistant) -> None: assert state.state == "off" +async def test_airzone_select_sys_qadapt(hass: HomeAssistant) -> None: + """Test select system Q-Adapt.""" + + await async_init_integration(hass) + + put_q_adapt = { + API_DATA: { + API_SYSTEM_ID: 1, + API_Q_ADAPT: QAdapt.SILENCE, + } + } + + with pytest.raises(ServiceValidationError): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.system_1_q_adapt", + ATTR_OPTION: "Invalid", + }, + blocking=True, + ) + + with patch( + "homeassistant.components.airzone.AirzoneLocalApi.put_hvac", + return_value=put_q_adapt, + ): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.system_1_q_adapt", + ATTR_OPTION: "silence", + }, + blocking=True, + ) + + state = hass.states.get("select.system_1_q_adapt") + assert state.state == "silence" + + put_q_adapt = { + API_DATA: { + API_SYSTEM_ID: 2, + API_Q_ADAPT: QAdapt.SILENCE, + } + } + + with ( + patch( + "homeassistant.components.airzone.AirzoneLocalApi.put_hvac", + return_value=put_q_adapt, + ), + pytest.raises(HomeAssistantError), + ): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.system_1_q_adapt", + ATTR_OPTION: "silence", + }, + blocking=True, + ) + + async def test_airzone_select_sleep(hass: HomeAssistant) -> None: """Test select sleep.""" diff --git a/tests/components/alarm_control_panel/test_condition.py b/tests/components/alarm_control_panel/test_condition.py new file mode 100644 index 00000000000..500b1c6c290 --- /dev/null +++ b/tests/components/alarm_control_panel/test_condition.py @@ -0,0 +1,264 @@ +"""Test alarm_control_panel conditions.""" + +from typing import Any + +import pytest + +from homeassistant.components.alarm_control_panel import ( + AlarmControlPanelEntityFeature, + AlarmControlPanelState, +) +from homeassistant.const import ATTR_SUPPORTED_FEATURES +from homeassistant.core import HomeAssistant + +from tests.components import ( + ConditionStateDescription, + assert_condition_gated_by_labs_flag, + create_target_condition, + other_states, + parametrize_condition_states_all, + parametrize_condition_states_any, + parametrize_target_entities, + set_or_remove_state, + target_entities, +) + + +@pytest.fixture +async def target_alarm_control_panels(hass: HomeAssistant) -> list[str]: + """Create multiple alarm_control_panel entities associated with different targets.""" + return (await target_entities(hass, "alarm_control_panel"))["included"] + + +@pytest.mark.parametrize( + "condition", + [ + "alarm_control_panel.is_armed", + "alarm_control_panel.is_armed_away", + "alarm_control_panel.is_armed_home", + "alarm_control_panel.is_armed_night", + "alarm_control_panel.is_armed_vacation", + "alarm_control_panel.is_disarmed", + "alarm_control_panel.is_triggered", + ], +) +async def test_alarm_control_panel_conditions_gated_by_labs_flag( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str +) -> None: + """Test the alarm_control_panel conditions are gated by the labs flag.""" + await assert_condition_gated_by_labs_flag(hass, caplog, condition) + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("alarm_control_panel"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_any( + condition="alarm_control_panel.is_armed", + target_states=[ + AlarmControlPanelState.ARMED_AWAY, + AlarmControlPanelState.ARMED_CUSTOM_BYPASS, + AlarmControlPanelState.ARMED_HOME, + AlarmControlPanelState.ARMED_NIGHT, + AlarmControlPanelState.ARMED_VACATION, + ], + other_states=[ + AlarmControlPanelState.ARMING, + AlarmControlPanelState.DISARMED, + AlarmControlPanelState.DISARMING, + AlarmControlPanelState.PENDING, + AlarmControlPanelState.TRIGGERED, + ], + ), + *parametrize_condition_states_any( + condition="alarm_control_panel.is_armed_away", + target_states=[AlarmControlPanelState.ARMED_AWAY], + other_states=other_states(AlarmControlPanelState.ARMED_AWAY), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_AWAY + }, + ), + *parametrize_condition_states_any( + condition="alarm_control_panel.is_armed_home", + target_states=[AlarmControlPanelState.ARMED_HOME], + other_states=other_states(AlarmControlPanelState.ARMED_HOME), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_HOME + }, + ), + *parametrize_condition_states_any( + condition="alarm_control_panel.is_armed_night", + target_states=[AlarmControlPanelState.ARMED_NIGHT], + other_states=other_states(AlarmControlPanelState.ARMED_NIGHT), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_NIGHT + }, + ), + *parametrize_condition_states_any( + condition="alarm_control_panel.is_armed_vacation", + target_states=[AlarmControlPanelState.ARMED_VACATION], + other_states=other_states(AlarmControlPanelState.ARMED_VACATION), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_VACATION + }, + ), + *parametrize_condition_states_any( + condition="alarm_control_panel.is_disarmed", + target_states=[AlarmControlPanelState.DISARMED], + other_states=other_states(AlarmControlPanelState.DISARMED), + ), + *parametrize_condition_states_any( + condition="alarm_control_panel.is_triggered", + target_states=[AlarmControlPanelState.TRIGGERED], + other_states=other_states(AlarmControlPanelState.TRIGGERED), + ), + ], +) +async def test_alarm_control_panel_state_condition_behavior_any( + hass: HomeAssistant, + target_alarm_control_panels: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the alarm_control_panel state condition with the 'any' behavior.""" + other_entity_ids = set(target_alarm_control_panels) - {entity_id} + + # Set all alarm_control_panels, including the tested alarm_control_panel, to the initial state + for eid in target_alarm_control_panels: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="any", + ) + + for state in states: + included_state = state["included"] + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + # Check if changing other alarm_control_panels also passes the condition + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("alarm_control_panel"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_all( + condition="alarm_control_panel.is_armed", + target_states=[ + AlarmControlPanelState.ARMED_AWAY, + AlarmControlPanelState.ARMED_CUSTOM_BYPASS, + AlarmControlPanelState.ARMED_HOME, + AlarmControlPanelState.ARMED_NIGHT, + AlarmControlPanelState.ARMED_VACATION, + ], + other_states=[ + AlarmControlPanelState.ARMING, + AlarmControlPanelState.DISARMED, + AlarmControlPanelState.DISARMING, + AlarmControlPanelState.PENDING, + AlarmControlPanelState.TRIGGERED, + ], + ), + *parametrize_condition_states_all( + condition="alarm_control_panel.is_armed_away", + target_states=[AlarmControlPanelState.ARMED_AWAY], + other_states=other_states(AlarmControlPanelState.ARMED_AWAY), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_AWAY + }, + ), + *parametrize_condition_states_all( + condition="alarm_control_panel.is_armed_home", + target_states=[AlarmControlPanelState.ARMED_HOME], + other_states=other_states(AlarmControlPanelState.ARMED_HOME), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_HOME + }, + ), + *parametrize_condition_states_all( + condition="alarm_control_panel.is_armed_night", + target_states=[AlarmControlPanelState.ARMED_NIGHT], + other_states=other_states(AlarmControlPanelState.ARMED_NIGHT), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_NIGHT + }, + ), + *parametrize_condition_states_all( + condition="alarm_control_panel.is_armed_vacation", + target_states=[AlarmControlPanelState.ARMED_VACATION], + other_states=other_states(AlarmControlPanelState.ARMED_VACATION), + additional_attributes={ + ATTR_SUPPORTED_FEATURES: AlarmControlPanelEntityFeature.ARM_VACATION + }, + ), + *parametrize_condition_states_all( + condition="alarm_control_panel.is_disarmed", + target_states=[AlarmControlPanelState.DISARMED], + other_states=other_states(AlarmControlPanelState.DISARMED), + ), + *parametrize_condition_states_all( + condition="alarm_control_panel.is_triggered", + target_states=[AlarmControlPanelState.TRIGGERED], + other_states=other_states(AlarmControlPanelState.TRIGGERED), + ), + ], +) +async def test_alarm_control_panel_state_condition_behavior_all( + hass: HomeAssistant, + target_alarm_control_panels: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the alarm_control_panel state condition with the 'all' behavior.""" + other_entity_ids = set(target_alarm_control_panels) - {entity_id} + + # Set all alarm_control_panels, including the tested alarm_control_panel, to the initial state + for eid in target_alarm_control_panels: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="all", + ) + + for state in states: + included_state = state["included"] + + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true_first_entity"] + + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + + assert condition(hass) == state["condition_true"] diff --git a/tests/components/alarm_control_panel/test_device_action.py b/tests/components/alarm_control_panel/test_device_action.py index d52ee5733a1..0774353f5f3 100644 --- a/tests/components/alarm_control_panel/test_device_action.py +++ b/tests/components/alarm_control_panel/test_device_action.py @@ -25,11 +25,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_action_types"), [ diff --git a/tests/components/alarm_control_panel/test_device_condition.py b/tests/components/alarm_control_panel/test_device_condition.py index 37cbc466e6d..9d098a9b30b 100644 --- a/tests/components/alarm_control_panel/test_device_condition.py +++ b/tests/components/alarm_control_panel/test_device_condition.py @@ -18,11 +18,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_condition_types"), [ diff --git a/tests/components/alarm_control_panel/test_device_trigger.py b/tests/components/alarm_control_panel/test_device_trigger.py index 979bc33bb00..d5ad857fd1b 100644 --- a/tests/components/alarm_control_panel/test_device_trigger.py +++ b/tests/components/alarm_control_panel/test_device_trigger.py @@ -26,11 +26,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_trigger_types"), [ diff --git a/tests/components/alarm_control_panel/test_trigger.py b/tests/components/alarm_control_panel/test_trigger.py index ff04f0110a7..f6c67beea92 100644 --- a/tests/components/alarm_control_panel/test_trigger.py +++ b/tests/components/alarm_control_panel/test_trigger.py @@ -1,8 +1,6 @@ """Test alarm control panel triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -14,7 +12,7 @@ from homeassistant.const import ATTR_LABEL_ID, ATTR_SUPPORTED_FEATURES, CONF_ENT from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, other_states, parametrize_target_entities, @@ -24,21 +22,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_alarm_control_panels(hass: HomeAssistant) -> list[str]: """Create multiple alarm control panel entities associated with different targets.""" @@ -70,7 +53,7 @@ async def test_alarm_control_panel_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("alarm_control_panel"), @@ -152,7 +135,7 @@ async def test_alarm_control_panel_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the alarm control panel state trigger fires when any alarm control panel state changes to a specific state.""" other_entity_ids = set(target_alarm_control_panels) - {entity_id} @@ -181,7 +164,7 @@ async def test_alarm_control_panel_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("alarm_control_panel"), @@ -263,7 +246,7 @@ async def test_alarm_control_panel_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the alarm control panel state trigger fires when the first alarm control panel changes to a specific state.""" other_entity_ids = set(target_alarm_control_panels) - {entity_id} @@ -291,7 +274,7 @@ async def test_alarm_control_panel_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("alarm_control_panel"), @@ -373,7 +356,7 @@ async def test_alarm_control_panel_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the alarm_control_panel state trigger fires when the last alarm_control_panel changes to a specific state.""" other_entity_ids = set(target_alarm_control_panels) - {entity_id} diff --git a/tests/components/alexa_devices/snapshots/test_binary_sensor.ambr b/tests/components/alexa_devices/snapshots/test_binary_sensor.ambr index c6b9a2afa08..874e0d5b35c 100644 --- a/tests/components/alexa_devices/snapshots/test_binary_sensor.ambr +++ b/tests/components/alexa_devices/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/alexa_devices/snapshots/test_notify.ambr b/tests/components/alexa_devices/snapshots/test_notify.ambr index 64776c14420..5dd78166ce9 100644 --- a/tests/components/alexa_devices/snapshots/test_notify.ambr +++ b/tests/components/alexa_devices/snapshots/test_notify.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Announce', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speak', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/alexa_devices/snapshots/test_sensor.ambr b/tests/components/alexa_devices/snapshots/test_sensor.ambr index 38565a46879..916fd36c038 100644 --- a/tests/components/alexa_devices/snapshots/test_sensor.ambr +++ b/tests/components/alexa_devices/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next alarm', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next reminder', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next timer', 'options': dict({ }), 'original_device_class': , @@ -169,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/alexa_devices/snapshots/test_switch.ambr b/tests/components/alexa_devices/snapshots/test_switch.ambr index 3ce484cf95b..14343e21302 100644 --- a/tests/components/alexa_devices/snapshots/test_switch.ambr +++ b/tests/components/alexa_devices/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Do not disturb', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/altruist/snapshots/test_sensor.ambr b/tests/components/altruist/snapshots/test_sensor.ambr index 9340e10cbe8..be65db990f6 100644 --- a/tests/components/altruist/snapshots/test_sensor.ambr +++ b/tests/components/altruist/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BME280 humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BME280 pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BME280 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -249,6 +253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -305,6 +310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -361,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -417,6 +424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiation level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -472,6 +480,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/ambient_network/snapshots/test_sensor.ambr b/tests/components/ambient_network/snapshots/test_sensor.ambr index 6d88a142c34..78ef107d479 100644 --- a/tests/components/ambient_network/snapshots/test_sensor.ambr +++ b/tests/components/ambient_network/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Absolute pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -260,6 +264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hourly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -321,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -379,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irradiance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -435,6 +442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last rain', 'options': dict({ }), 'original_device_class': , @@ -488,6 +496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max daily gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -549,6 +558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -610,6 +620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -671,6 +682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -729,6 +741,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -786,6 +799,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -847,6 +861,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -905,6 +920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -966,6 +982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1027,6 +1044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Absolute pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1088,6 +1106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1149,6 +1168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1207,6 +1227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1265,6 +1286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hourly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1326,6 +1348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1384,6 +1407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irradiance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1440,6 +1464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last rain', 'options': dict({ }), 'original_device_class': , @@ -1493,6 +1518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max daily gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1554,6 +1580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1615,6 +1642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1676,6 +1704,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1734,6 +1763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1791,6 +1821,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1852,6 +1883,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1910,6 +1942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1971,6 +2004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2032,6 +2066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Absolute pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2092,6 +2127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2152,6 +2188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2209,6 +2246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2266,6 +2304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hourly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2326,6 +2365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2383,6 +2423,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irradiance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2440,6 +2481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max daily gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2500,6 +2542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2560,6 +2603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2620,6 +2664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2677,6 +2722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2733,6 +2779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly rain', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2793,6 +2840,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2850,6 +2898,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2910,6 +2959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/analytics/test_analytics.py b/tests/components/analytics/test_analytics.py index f2789b6f479..0dfac987603 100644 --- a/tests/components/analytics/test_analytics.py +++ b/tests/components/analytics/test_analytics.py @@ -1201,6 +1201,7 @@ async def test_devices_payload_with_entities( entity_category=EntityCategory.CONFIG, has_entity_name=True, original_device_class=NumberDeviceClass.TEMPERATURE, + suggested_object_id="hue_1", ) hass.states.async_set("number.hue_1", "2") # Entity with assumed state @@ -1210,6 +1211,7 @@ async def test_devices_payload_with_entities( unique_id="2", device_id=device_entry.id, has_entity_name=True, + suggested_object_id="hue_2", ) hass.states.async_set("light.hue_2", "on", {ATTR_ASSUMED_STATE: True}) # Entity from a different integration diff --git a/tests/components/analytics_insights/snapshots/test_sensor.ambr b/tests/components/analytics_insights/snapshots/test_sensor.ambr index 4b71e2fef3e..7c85d24c049 100644 --- a/tests/components/analytics_insights/snapshots/test_sensor.ambr +++ b/tests/components/analytics_insights/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'core_samba', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'hacs (custom)', 'options': dict({ }), 'original_device_class': None, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'myq', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'spotify', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total active installations', 'options': dict({ }), 'original_device_class': None, @@ -282,6 +287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total reported integrations', 'options': dict({ }), 'original_device_class': None, @@ -334,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'YouTube', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/anglian_water/snapshots/test_sensor.ambr b/tests/components/anglian_water/snapshots/test_sensor.ambr index d63bd9296d2..377509fb2e6 100644 --- a/tests/components/anglian_water/snapshots/test_sensor.ambr +++ b/tests/components/anglian_water/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latest reading', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "Yesterday's sewerage cost", 'options': dict({ }), 'original_device_class': , @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "Yesterday's usage", 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "Yesterday's water cost", 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/aosmith/snapshots/test_select.ambr b/tests/components/aosmith/snapshots/test_select.ambr index 9e0c10319c3..8f2dec51fa0 100644 --- a/tests/components/aosmith/snapshots/test_select.ambr +++ b/tests/components/aosmith/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'hot_water_plus_level', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/aosmith/snapshots/test_sensor.ambr b/tests/components/aosmith/snapshots/test_sensor.ambr index ae0752ee1ed..b613557882b 100644 --- a/tests/components/aosmith/snapshots/test_sensor.ambr +++ b/tests/components/aosmith/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water availability', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/aosmith/snapshots/test_water_heater.ambr b/tests/components/aosmith/snapshots/test_water_heater.ambr index 452b2a05e2e..f94c9d32128 100644 --- a/tests/components/aosmith/snapshots/test_water_heater.ambr +++ b/tests/components/aosmith/snapshots/test_water_heater.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -87,6 +88,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/apcupsd/__init__.py b/tests/components/apcupsd/__init__.py index 27ddd478b9b..8d53a4c8639 100644 --- a/tests/components/apcupsd/__init__.py +++ b/tests/components/apcupsd/__init__.py @@ -10,7 +10,7 @@ CONF_DATA: Final = {CONF_HOST: "test", CONF_PORT: 1234} MOCK_STATUS: Final = { "APC": "001,038,0985", - "DATE": "1970-01-01 00:00:00 0000", + "DATE": "1970-01-01 00:00:00 +0000", "VERSION": "3.14.14 (31 May 2016) unknown", "CABLE": "USB Cable", "DRIVER": "USB UPS Driver", @@ -19,6 +19,7 @@ MOCK_STATUS: Final = { "APCMODEL": "Back-UPS ES 600", "MODEL": "Back-UPS ES 600", "STATUS": "ONLINE", + "STARTTIME": "2006-01-01 00:00:00 +0500", "LINEV": "124.0 Volts", "LOADPCT": "14.0 Percent", "BCHARGE": "100.0 Percent", @@ -36,11 +37,11 @@ MOCK_STATUS: Final = { "OUTCURNT": "0.88 Amps", "LASTXFER": "Automatic or explicit self test", "NUMXFERS": "1", - "XONBATT": "1970-01-01 00:00:00 0000", + "XONBATT": "1970-01-01 00:00:00 +0000", "TONBATT": "0 Seconds", "CUMONBATT": "8 Seconds", - "XOFFBATT": "1970-01-01 00:00:00 0000", - "LASTSTEST": "1970-01-01 00:00:00 0000", + "XOFFBATT": "1970-01-01 00:00:00 +0000", + "LASTSTEST": "1970-01-01 00:00:00 +0000", "SELFTEST": "NO", "STESTI": "7 days", "STATFLAG": "0x05000008", @@ -50,7 +51,8 @@ MOCK_STATUS: Final = { "NOMBATTV": "12.0 Volts", "NOMPOWER": "330 Watts", "FIRMWARE": "928.a8 .D USB FW:a8", - "END APC": "1970-01-01 00:00:00 0000", + "MASTERUPD": "1970-01-01 00:00:00 +0000", + "END APC": "1970-01-01 00:00:00 +0000", } # Minimal status adapted from http://www.apcupsd.org/manual/manual.html#apcaccess-test. @@ -58,13 +60,13 @@ MOCK_STATUS: Final = { # of the integration to handle such cases. MOCK_MINIMAL_STATUS: Final = { "APC": "001,012,0319", - "DATE": "1970-01-01 00:00:00 0000", + "DATE": "1970-01-01 00:00:00 +0000", "RELEASE": "3.8.5", "CABLE": "APC Cable 940-0128A", "UPSMODE": "Stand Alone", - "STARTTIME": "1970-01-01 00:00:00 0000", + "STARTTIME": "1970-01-01 00:00:00 +0000", "LINEFAIL": "OK", "BATTSTAT": "OK", "STATFLAG": "0x008", - "END APC": "1970-01-01 00:00:00 0000", + "END APC": "1970-01-01 00:00:00 +0000", } diff --git a/tests/components/apcupsd/snapshots/test_binary_sensor.ambr b/tests/components/apcupsd/snapshots/test_binary_sensor.ambr index 898525cde9c..28c12a16731 100644 --- a/tests/components/apcupsd/snapshots/test_binary_sensor.ambr +++ b/tests/components/apcupsd/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Online status', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/apcupsd/snapshots/test_diagnostics.ambr b/tests/components/apcupsd/snapshots/test_diagnostics.ambr index 669654c75bb..e7c31dd91bd 100644 --- a/tests/components/apcupsd/snapshots/test_diagnostics.ambr +++ b/tests/components/apcupsd/snapshots/test_diagnostics.ambr @@ -9,17 +9,18 @@ 'BCHARGE': '100.0 Percent', 'CABLE': 'USB Cable', 'CUMONBATT': '8 Seconds', - 'DATE': '1970-01-01 00:00:00 0000', + 'DATE': '1970-01-01 00:00:00 +0000', 'DRIVER': 'USB UPS Driver', - 'END APC': '1970-01-01 00:00:00 0000', + 'END APC': '1970-01-01 00:00:00 +0000', 'FIRMWARE': '928.a8 .D USB FW:a8', 'HITRANS': '139.0 Volts', 'ITEMP': '34.6 C Internal', - 'LASTSTEST': '1970-01-01 00:00:00 0000', + 'LASTSTEST': '1970-01-01 00:00:00 +0000', 'LASTXFER': 'Automatic or explicit self test', 'LINEV': '124.0 Volts', 'LOADPCT': '14.0 Percent', 'LOTRANS': '92.0 Volts', + 'MASTERUPD': '1970-01-01 00:00:00 +0000', 'MAXTIME': '0 Seconds', 'MBATTCHG': '5 Percent', 'MINTIMEL': '3 Minutes', @@ -33,6 +34,7 @@ 'SELFTEST': 'NO', 'SENSE': 'Medium', 'SERIALNO': '**REDACTED**', + 'STARTTIME': '2006-01-01 00:00:00 +0500', 'STATFLAG': '0x05000008', 'STATUS': 'ONLINE', 'STESTI': '7 days', @@ -41,7 +43,7 @@ 'UPSMODE': 'Stand Alone', 'UPSNAME': 'MyUPS', 'VERSION': '3.14.14 (31 May 2016) unknown', - 'XOFFBATT': '1970-01-01 00:00:00 0000', - 'XONBATT': '1970-01-01 00:00:00 0000', + 'XOFFBATT': '1970-01-01 00:00:00 +0000', + 'XONBATT': '1970-01-01 00:00:00 +0000', }) # --- diff --git a/tests/components/apcupsd/snapshots/test_sensor.ambr b/tests/components/apcupsd/snapshots/test_sensor.ambr index 73b349650b8..37d87c395bf 100644 --- a/tests/components/apcupsd/snapshots/test_sensor.ambr +++ b/tests/components/apcupsd/snapshots/test_sensor.ambr @@ -260,6 +260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm delay', 'options': dict({ }), 'original_device_class': None, @@ -311,6 +312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -362,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery nominal voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -415,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery replaced', 'options': dict({ }), 'original_device_class': None, @@ -463,6 +467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery shutdown', 'options': dict({ }), 'original_device_class': None, @@ -512,6 +517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery timeout', 'options': dict({ }), 'original_device_class': None, @@ -563,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -617,6 +624,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cable type', 'options': dict({ }), 'original_device_class': None, @@ -665,6 +673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daemon version', 'options': dict({ }), 'original_device_class': None, @@ -713,6 +722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Date and time', 'options': dict({ }), 'original_device_class': None, @@ -737,7 +747,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1970-01-01 00:00:00 0000', + 'state': '1970-01-01 00:00:00 +0000', }) # --- # name: test_sensor[sensor.myups_driver-entry] @@ -761,6 +771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Driver', 'options': dict({ }), 'original_device_class': None, @@ -809,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware version', 'options': dict({ }), 'original_device_class': None, @@ -859,6 +871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -915,6 +928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -969,9 +983,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last self-test', 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Last self-test', 'platform': 'apcupsd', @@ -986,6 +1001,7 @@ # name: test_sensor[sensor.myups_last_self_test-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', 'friendly_name': 'MyUPS Last self-test', }), 'context': , @@ -993,7 +1009,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1970-01-01 00:00:00 0000', + 'state': '1970-01-01T00:00:00+00:00', }) # --- # name: test_sensor[sensor.myups_last_transfer-entry] @@ -1017,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last transfer', 'options': dict({ }), 'original_device_class': None, @@ -1067,6 +1084,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load', 'options': dict({ }), 'original_device_class': None, @@ -1096,6 +1114,56 @@ 'state': '14.0', }) # --- +# name: test_sensor[sensor.myups_master_update-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.myups_master_update', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Master update', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Master update', + 'platform': 'apcupsd', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'master_update', + 'unique_id': 'XXXXXXXXXXXX_masterupd', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[sensor.myups_master_update-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', + 'friendly_name': 'MyUPS Master update', + }), + 'context': , + 'entity_id': 'sensor.myups_master_update', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1970-01-01T00:00:00+00:00', + }) +# --- # name: test_sensor[sensor.myups_mode-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1117,6 +1185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -1165,6 +1234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Model', 'options': dict({ }), 'original_device_class': None, @@ -1213,6 +1283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Model', 'options': dict({ }), 'original_device_class': None, @@ -1261,6 +1332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Name', 'options': dict({ }), 'original_device_class': None, @@ -1309,6 +1381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nominal apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1362,6 +1435,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nominal input voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1415,6 +1489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nominal output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1470,6 +1545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1524,6 +1600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-test interval', 'options': dict({ }), 'original_device_class': None, @@ -1573,6 +1650,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-test result', 'options': dict({ }), 'original_device_class': None, @@ -1621,6 +1699,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1669,6 +1748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Serial number', 'options': dict({ }), 'original_device_class': None, @@ -1717,6 +1797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Shutdown time', 'options': dict({ }), 'original_device_class': None, @@ -1745,6 +1826,56 @@ 'state': '3', }) # --- +# name: test_sensor[sensor.myups_startup_time-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.myups_startup_time', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Startup time', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Startup time', + 'platform': 'apcupsd', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'startup_time', + 'unique_id': 'XXXXXXXXXXXX_starttime', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[sensor.myups_startup_time-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', + 'friendly_name': 'MyUPS Startup time', + }), + 'context': , + 'entity_id': 'sensor.myups_startup_time', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2005-12-31T19:00:00+00:00', + }) +# --- # name: test_sensor[sensor.myups_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1766,6 +1897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -1814,6 +1946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status data', 'options': dict({ }), 'original_device_class': None, @@ -1862,6 +1995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status date', 'options': dict({ }), 'original_device_class': None, @@ -1886,7 +2020,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1970-01-01 00:00:00 0000', + 'state': '1970-01-01 00:00:00 +0000', }) # --- # name: test_sensor[sensor.myups_status_flag-entry] @@ -1910,6 +2044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status flag', 'options': dict({ }), 'original_device_class': None, @@ -1960,6 +2095,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2016,6 +2152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time on battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2072,6 +2209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total time on battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2128,6 +2266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfer count', 'options': dict({ }), 'original_device_class': None, @@ -2177,9 +2316,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfer from battery', 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Transfer from battery', 'platform': 'apcupsd', @@ -2194,6 +2334,7 @@ # name: test_sensor[sensor.myups_transfer_from_battery-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', 'friendly_name': 'MyUPS Transfer from battery', }), 'context': , @@ -2201,7 +2342,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1970-01-01 00:00:00 0000', + 'state': '1970-01-01T00:00:00+00:00', }) # --- # name: test_sensor[sensor.myups_transfer_high-entry] @@ -2225,6 +2366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfer high', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2278,6 +2420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfer low', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2331,9 +2474,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfer to battery', 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Transfer to battery', 'platform': 'apcupsd', @@ -2348,6 +2492,7 @@ # name: test_sensor[sensor.myups_transfer_to_battery-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', 'friendly_name': 'MyUPS Transfer to battery', }), 'context': , @@ -2355,6 +2500,6 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '1970-01-01 00:00:00 0000', + 'state': '1970-01-01T00:00:00+00:00', }) # --- diff --git a/tests/components/apcupsd/test_sensor.py b/tests/components/apcupsd/test_sensor.py index 2842bdf1258..2da69b89531 100644 --- a/tests/components/apcupsd/test_sensor.py +++ b/tests/components/apcupsd/test_sensor.py @@ -3,6 +3,7 @@ from datetime import timedelta from unittest.mock import AsyncMock +import dateutil.parser import pytest from syrupy.assertion import SnapshotAssertion @@ -151,13 +152,17 @@ async def test_sensor_unknown( # Simulate an event (a self test) such that "LASTSTEST" field is being reported, the state of # the sensor should be properly updated with the corresponding value. + last_self_test_value = "1970-01-01 00:00:00 +0000" mock_request_status.return_value = MOCK_MINIMAL_STATUS | { - "LASTSTEST": "1970-01-01 00:00:00 0000" + "LASTSTEST": last_self_test_value } future = utcnow() + timedelta(minutes=2) async_fire_time_changed(hass, future) await hass.async_block_till_done() - assert hass.states.get(last_self_test_id).state == "1970-01-01 00:00:00 0000" + assert ( + hass.states.get(last_self_test_id).state + == dateutil.parser.parse(last_self_test_value).isoformat() + ) # Simulate another event (e.g., daemon restart) such that "LASTSTEST" is no longer reported. mock_request_status.return_value = MOCK_MINIMAL_STATUS diff --git a/tests/components/apsystems/snapshots/test_binary_sensor.ambr b/tests/components/apsystems/snapshots/test_binary_sensor.ambr index d8088288461..c17df2691f8 100644 --- a/tests/components/apsystems/snapshots/test_binary_sensor.ambr +++ b/tests/components/apsystems/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC 1 short circuit error status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC 2 short circuit error status', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-grid status', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output fault status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/apsystems/snapshots/test_number.ambr b/tests/components/apsystems/snapshots/test_number.ambr index 7d02e6e16c4..871e236d7d2 100644 --- a/tests/components/apsystems/snapshots/test_number.ambr +++ b/tests/components/apsystems/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max output', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/apsystems/snapshots/test_sensor.ambr b/tests/components/apsystems/snapshots/test_sensor.ambr index f163c4db840..01470a917a7 100644 --- a/tests/components/apsystems/snapshots/test_sensor.ambr +++ b/tests/components/apsystems/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime production of P1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime production of P2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power of P1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power of P2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production of today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production of today from P1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production of today from P2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total lifetime production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/apsystems/snapshots/test_switch.ambr b/tests/components/apsystems/snapshots/test_switch.ambr index 2b3ccbab6c4..ba6b1295cc3 100644 --- a/tests/components/apsystems/snapshots/test_switch.ambr +++ b/tests/components/apsystems/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/aquacell/snapshots/test_sensor.ambr b/tests/components/aquacell/snapshots/test_sensor.ambr index c24a7f43cfe..198fe481c4b 100644 --- a/tests/components/aquacell/snapshots/test_sensor.ambr +++ b/tests/components/aquacell/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last update', 'options': dict({ }), 'original_device_class': , @@ -121,6 +123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt left side percentage', 'options': dict({ }), 'original_device_class': None, @@ -171,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt left side time remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -226,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt right side percentage', 'options': dict({ }), 'original_device_class': None, @@ -276,6 +281,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt right side time remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -335,6 +341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/arcam_fmj/test_device_trigger.py b/tests/components/arcam_fmj/test_device_trigger.py index eb5cf1d7892..9e97d253711 100644 --- a/tests/components/arcam_fmj/test_device_trigger.py +++ b/tests/components/arcam_fmj/test_device_trigger.py @@ -1,7 +1,5 @@ """The tests for Arcam FMJ Receiver control device triggers.""" -import pytest - from homeassistant.components import automation from homeassistant.components.arcam_fmj.const import DOMAIN from homeassistant.components.device_automation import DeviceAutomationType @@ -12,11 +10,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/arve/snapshots/test_sensor.ambr b/tests/components/arve/snapshots/test_sensor.ambr index 18643ac1755..d386d0d234e 100644 --- a/tests/components/arve/snapshots/test_sensor.ambr +++ b/tests/components/arve/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality index', 'options': dict({ }), 'original_device_class': , @@ -59,6 +60,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -96,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -133,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -170,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -207,6 +212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -247,6 +253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total volatile organic compounds', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/assist_satellite/test_condition.py b/tests/components/assist_satellite/test_condition.py new file mode 100644 index 00000000000..2615a69fb4f --- /dev/null +++ b/tests/components/assist_satellite/test_condition.py @@ -0,0 +1,179 @@ +"""Test assist satellite conditions.""" + +from typing import Any + +import pytest + +from homeassistant.components.assist_satellite.entity import AssistSatelliteState +from homeassistant.core import HomeAssistant + +from tests.components import ( + ConditionStateDescription, + assert_condition_gated_by_labs_flag, + create_target_condition, + other_states, + parametrize_condition_states_all, + parametrize_condition_states_any, + parametrize_target_entities, + set_or_remove_state, + target_entities, +) + + +@pytest.fixture +async def target_assist_satellites(hass: HomeAssistant) -> list[str]: + """Create multiple assist satellite entities associated with different targets.""" + return (await target_entities(hass, "assist_satellite"))["included"] + + +@pytest.mark.parametrize( + "condition", + [ + "assist_satellite.is_idle", + "assist_satellite.is_listening", + "assist_satellite.is_processing", + "assist_satellite.is_responding", + ], +) +async def test_assist_satellite_conditions_gated_by_labs_flag( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str +) -> None: + """Test the assist satellite conditions are gated by the labs flag.""" + await assert_condition_gated_by_labs_flag(hass, caplog, condition) + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("assist_satellite"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_any( + condition="assist_satellite.is_idle", + target_states=[AssistSatelliteState.IDLE], + other_states=other_states(AssistSatelliteState.IDLE), + ), + *parametrize_condition_states_any( + condition="assist_satellite.is_listening", + target_states=[AssistSatelliteState.LISTENING], + other_states=other_states(AssistSatelliteState.LISTENING), + ), + *parametrize_condition_states_any( + condition="assist_satellite.is_processing", + target_states=[AssistSatelliteState.PROCESSING], + other_states=other_states(AssistSatelliteState.PROCESSING), + ), + *parametrize_condition_states_any( + condition="assist_satellite.is_responding", + target_states=[AssistSatelliteState.RESPONDING], + other_states=other_states(AssistSatelliteState.RESPONDING), + ), + ], +) +async def test_assist_satellite_state_condition_behavior_any( + hass: HomeAssistant, + target_assist_satellites: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the assist satellite state condition with the 'any' behavior.""" + other_entity_ids = set(target_assist_satellites) - {entity_id} + + # Set all assist satellites, including the tested one, to the initial state + for eid in target_assist_satellites: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="any", + ) + + for state in states: + included_state = state["included"] + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + # Check if changing other assist satellites also passes the condition + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("assist_satellite"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_all( + condition="assist_satellite.is_idle", + target_states=[AssistSatelliteState.IDLE], + other_states=other_states(AssistSatelliteState.IDLE), + ), + *parametrize_condition_states_all( + condition="assist_satellite.is_listening", + target_states=[AssistSatelliteState.LISTENING], + other_states=other_states(AssistSatelliteState.LISTENING), + ), + *parametrize_condition_states_all( + condition="assist_satellite.is_processing", + target_states=[AssistSatelliteState.PROCESSING], + other_states=other_states(AssistSatelliteState.PROCESSING), + ), + *parametrize_condition_states_all( + condition="assist_satellite.is_responding", + target_states=[AssistSatelliteState.RESPONDING], + other_states=other_states(AssistSatelliteState.RESPONDING), + ), + ], +) +async def test_assist_satellite_state_condition_behavior_all( + hass: HomeAssistant, + target_assist_satellites: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the assist satellite state condition with the 'all' behavior.""" + other_entity_ids = set(target_assist_satellites) - {entity_id} + + # Set all assist satellites, including the tested one, to the initial state + for eid in target_assist_satellites: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="all", + ) + + for state in states: + included_state = state["included"] + + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true_first_entity"] + + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + + assert condition(hass) == state["condition_true"] diff --git a/tests/components/assist_satellite/test_trigger.py b/tests/components/assist_satellite/test_trigger.py index 8111d8f96e7..5b49d614c75 100644 --- a/tests/components/assist_satellite/test_trigger.py +++ b/tests/components/assist_satellite/test_trigger.py @@ -1,8 +1,6 @@ """Test assist satellite triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, other_states, parametrize_target_entities, @@ -21,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_assist_satellites(hass: HomeAssistant) -> list[str]: """Create multiple assist satellite entities associated with different targets.""" @@ -64,7 +47,7 @@ async def test_assist_satellite_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("assist_satellite"), @@ -103,7 +86,7 @@ async def test_assist_satellite_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the assist satellite state trigger fires when any assist satellite state changes to a specific state.""" other_entity_ids = set(target_assist_satellites) - {entity_id} @@ -132,7 +115,7 @@ async def test_assist_satellite_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("assist_satellite"), @@ -171,7 +154,7 @@ async def test_assist_satellite_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the assist satellite state trigger fires when the first assist satellite changes to a specific state.""" other_entity_ids = set(target_assist_satellites) - {entity_id} @@ -199,7 +182,7 @@ async def test_assist_satellite_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("assist_satellite"), @@ -238,7 +221,7 @@ async def test_assist_satellite_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the assist_satellite state trigger fires when the last assist_satellite changes to a specific state.""" other_entity_ids = set(target_assist_satellites) - {entity_id} diff --git a/tests/components/autarco/snapshots/test_sensor.ambr b/tests/components/autarco/snapshots/test_sensor.ambr index 73a07d71656..32c410c8f0a 100644 --- a/tests/components/autarco/snapshots/test_sensor.ambr +++ b/tests/components/autarco/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charged month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charged total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discharged month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discharged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discharged total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow now', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge', 'options': dict({ }), 'original_device_class': , @@ -467,6 +475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy AC output total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -523,6 +532,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power AC output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -579,6 +589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy AC output total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -635,6 +646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power AC output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -691,6 +703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -747,6 +760,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -803,6 +817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -859,6 +874,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/automation/conftest.py b/tests/components/automation/conftest.py deleted file mode 100644 index 1d2d39a463d..00000000000 --- a/tests/components/automation/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Conftest for automation tests.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/automation/test_init.py b/tests/components/automation/test_init.py index 6bacee92f5e..0eb618ed633 100644 --- a/tests/components/automation/test_init.py +++ b/tests/components/automation/test_init.py @@ -2232,7 +2232,7 @@ async def test_extraction_functions( assert automation.blueprint_in_automation(hass, "automation.test3") is None -async def test_extraction_functions_with_targets( +async def test_extraction_functions_with_trigger_targets( hass: HomeAssistant, device_registry: dr.DeviceRegistry, hass_ws_client: WebSocketGenerator, @@ -2428,6 +2428,211 @@ async def test_extraction_functions_with_targets( } +async def test_extraction_functions_with_condition_targets( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + hass_ws_client: WebSocketGenerator, +) -> None: + """Test extraction functions with targets in conditions.""" + config_entry = MockConfigEntry(domain="fake_integration", data={}) + config_entry.mock_state(hass, ConfigEntryState.LOADED) + config_entry.add_to_hass(hass) + + condition_device = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "00:00:00:00:00:02")}, + ) + + await async_setup_component(hass, "homeassistant", {}) + await async_setup_component(hass, "light", {"light": {"platform": "demo"}}) + await hass.async_block_till_done() + + # Enable the new_triggers_conditions feature flag to allow new-style conditions + assert await async_setup_component(hass, "labs", {}) + ws_client = await hass_ws_client(hass) + await ws_client.send_json_auto_id( + { + "type": "labs/update", + "domain": "automation", + "preview_feature": "new_triggers_conditions", + "enabled": True, + } + ) + msg = await ws_client.receive_json() + assert msg["success"] + await hass.async_block_till_done() + + assert await async_setup_component( + hass, + DOMAIN, + { + DOMAIN: [ + { + "alias": "test1", + "triggers": [ + {"trigger": "state", "entity_id": "sensor.trigger_state"}, + ], + "conditions": [ + # Single entity_id in target + { + "condition": "light.is_on", + "target": {"entity_id": "light.condition_entity"}, + "options": {"behavior": "any"}, + }, + # Multiple entity_ids in target + { + "condition": "light.is_on", + "target": { + "entity_id": [ + "light.condition_entity_list1", + "light.condition_entity_list2", + ] + }, + "options": {"behavior": "any"}, + }, + # Single device_id in target + { + "condition": "light.is_on", + "target": {"device_id": condition_device.id}, + "options": {"behavior": "any"}, + }, + # Multiple device_ids in target + { + "condition": "light.is_on", + "target": { + "device_id": [ + "target-device-1", + "target-device-2", + ] + }, + "options": {"behavior": "any"}, + }, + # Single area_id in target + { + "condition": "light.is_on", + "target": {"area_id": "area-condition-single"}, + "options": {"behavior": "any"}, + }, + # Multiple area_ids in target + { + "condition": "light.is_on", + "target": { + "area_id": ["area-condition-1", "area-condition-2"] + }, + "options": {"behavior": "any"}, + }, + # Single floor_id in target + { + "condition": "light.is_on", + "target": {"floor_id": "floor-condition-single"}, + "options": {"behavior": "any"}, + }, + # Multiple floor_ids in target + { + "condition": "light.is_on", + "target": { + "floor_id": ["floor-condition-1", "floor-condition-2"] + }, + "options": {"behavior": "any"}, + }, + # Single label_id in target + { + "condition": "light.is_on", + "target": {"label_id": "label-condition-single"}, + "options": {"behavior": "any"}, + }, + # Multiple label_ids in target + { + "condition": "light.is_on", + "target": { + "label_id": ["label-condition-1", "label-condition-2"] + }, + "options": {"behavior": "any"}, + }, + # Combined targets + { + "condition": "light.is_on", + "target": { + "entity_id": "light.combined_entity", + "device_id": "combined-device", + "area_id": "combined-area", + "floor_id": "combined-floor", + "label_id": "combined-label", + }, + "options": {"behavior": "any"}, + }, + ], + "actions": [ + { + "action": "test.script", + "data": {"entity_id": "light.action_entity"}, + }, + ], + }, + ] + }, + ) + + # Test entity extraction from condition targets + assert set(automation.entities_in_automation(hass, "automation.test1")) == { + "sensor.trigger_state", + "light.condition_entity", + "light.condition_entity_list1", + "light.condition_entity_list2", + "light.combined_entity", + "light.action_entity", + } + + # Test device extraction from condition targets + assert set(automation.devices_in_automation(hass, "automation.test1")) == { + condition_device.id, + "target-device-1", + "target-device-2", + "combined-device", + } + + # Test area extraction from condition targets + assert set(automation.areas_in_automation(hass, "automation.test1")) == { + "area-condition-single", + "area-condition-1", + "area-condition-2", + "combined-area", + } + + # Test floor extraction from condition targets + assert set(automation.floors_in_automation(hass, "automation.test1")) == { + "floor-condition-single", + "floor-condition-1", + "floor-condition-2", + "combined-floor", + } + + # Test label extraction from condition targets + assert set(automation.labels_in_automation(hass, "automation.test1")) == { + "label-condition-single", + "label-condition-1", + "label-condition-2", + "combined-label", + } + + # Test automations_with_* functions + assert set(automation.automations_with_entity(hass, "light.condition_entity")) == { + "automation.test1" + } + assert set(automation.automations_with_device(hass, condition_device.id)) == { + "automation.test1" + } + assert set(automation.automations_with_area(hass, "area-condition-single")) == { + "automation.test1" + } + assert set(automation.automations_with_floor(hass, "floor-condition-single")) == { + "automation.test1" + } + assert set(automation.automations_with_label(hass, "label-condition-single")) == { + "automation.test1" + } + + async def test_logbook_humanify_automation_triggered_event(hass: HomeAssistant) -> None: """Test humanifying Automation Trigger event.""" hass.config.components.add("recorder") diff --git a/tests/components/awair/snapshots/test_sensor.ambr b/tests/components/awair/snapshots/test_sensor.ambr index 2b1981eb27e..815bde609fb 100644 --- a/tests/components/awair/snapshots/test_sensor.ambr +++ b/tests/components/awair/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -242,6 +246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Score', 'options': dict({ }), 'original_device_class': None, @@ -295,6 +300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -353,6 +359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -408,6 +415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -463,6 +471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -518,6 +527,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -573,6 +583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Score', 'options': dict({ }), 'original_device_class': None, @@ -626,6 +637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -684,6 +696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -739,6 +752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -794,6 +808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -849,6 +864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Score', 'options': dict({ }), 'original_device_class': None, @@ -902,6 +918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -960,6 +977,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -1015,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1070,6 +1089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1124,6 +1144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -1179,6 +1200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Score', 'options': dict({ }), 'original_device_class': None, @@ -1232,6 +1254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1290,6 +1313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -1345,6 +1369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -1400,6 +1425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1455,6 +1481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1509,6 +1536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -1564,6 +1592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Score', 'options': dict({ }), 'original_device_class': None, @@ -1617,6 +1646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound level', 'options': dict({ }), 'original_device_class': , @@ -1671,6 +1701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1729,6 +1760,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -1784,6 +1816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Absolute humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1841,6 +1874,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -1895,6 +1929,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1952,6 +1987,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2006,6 +2042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -2060,6 +2097,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Score', 'options': dict({ }), 'original_device_class': None, @@ -2113,6 +2151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2170,6 +2209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/axis/snapshots/test_binary_sensor.ambr b/tests/components/axis/snapshots/test_binary_sensor.ambr index fb762800c12..6dc76f5e09d 100644 --- a/tests/components/axis/snapshots/test_binary_sensor.ambr +++ b/tests/components/axis/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DayNight 1', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Object Analytics Device1Scenario8', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound 1', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PIR sensor', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PIR 0', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fence Guard Profile 1', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion Guard Profile 1', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Loitering Guard Profile 1', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VMD4 Profile 1', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Object Analytics Scenario 1', 'options': dict({ }), 'original_device_class': , @@ -510,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VMD4 Camera1Profile9', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/axis/snapshots/test_camera.ambr b/tests/components/axis/snapshots/test_camera.ambr index 68b9cd07e53..f6416190278 100644 --- a/tests/components/axis/snapshots/test_camera.ambr +++ b/tests/components/axis/snapshots/test_camera.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/axis/snapshots/test_light.ambr b/tests/components/axis/snapshots/test_light.ambr index aec750ecda3..db8a35141da 100644 --- a/tests/components/axis/snapshots/test_light.ambr +++ b/tests/components/axis/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IR Light 0', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/axis/snapshots/test_switch.ambr b/tests/components/axis/snapshots/test_switch.ambr index 1e9a2d0b068..181184a7892 100644 --- a/tests/components/axis/snapshots/test_switch.ambr +++ b/tests/components/axis/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay 1', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay 1', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/azure_devops/snapshots/test_sensor.ambr b/tests/components/azure_devops/snapshots/test_sensor.ambr index 865cd79ee1f..9bdaa2573a5 100644 --- a/tests/components/azure_devops/snapshots/test_sensor.ambr +++ b/tests/components/azure_devops/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build', 'options': dict({ }), 'original_device_class': None, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build finish time', 'options': dict({ }), 'original_device_class': , @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build ID', 'options': dict({ }), 'original_device_class': None, @@ -177,6 +180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build queue time', 'options': dict({ }), 'original_device_class': , @@ -226,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build reason', 'options': dict({ }), 'original_device_class': None, @@ -274,6 +279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build result', 'options': dict({ }), 'original_device_class': None, @@ -322,6 +328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build source branch', 'options': dict({ }), 'original_device_class': None, @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build source version', 'options': dict({ }), 'original_device_class': None, @@ -418,6 +426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build start time', 'options': dict({ }), 'original_device_class': , @@ -467,6 +476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CI latest build URL', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/backup/snapshots/test_event.ambr b/tests/components/backup/snapshots/test_event.ambr index 78f60bf8d20..a5393e93128 100644 --- a/tests/components/backup/snapshots/test_event.ambr +++ b/tests/components/backup/snapshots/test_event.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Automatic backup', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/backup/snapshots/test_sensors.ambr b/tests/components/backup/snapshots/test_sensors.ambr index 034ca91239b..4348d19b385 100644 --- a/tests/components/backup/snapshots/test_sensors.ambr +++ b/tests/components/backup/snapshots/test_sensors.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup Manager state', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last attempted automatic backup', 'options': dict({ }), 'original_device_class': , @@ -133,6 +135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last successful automatic backup', 'options': dict({ }), 'original_device_class': , @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next scheduled automatic backup', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/balboa/snapshots/test_binary_sensor.ambr b/tests/components/balboa/snapshots/test_binary_sensor.ambr index 51f1dfa8e3f..1e9b1e046f9 100644 --- a/tests/components/balboa/snapshots/test_binary_sensor.ambr +++ b/tests/components/balboa/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Circulation pump', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 1', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 2', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/balboa/snapshots/test_climate.ambr b/tests/components/balboa/snapshots/test_climate.ambr index b616c77de7d..bad83ab7b42 100644 --- a/tests/components/balboa/snapshots/test_climate.ambr +++ b/tests/components/balboa/snapshots/test_climate.ambr @@ -31,6 +31,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/balboa/snapshots/test_event.ambr b/tests/components/balboa/snapshots/test_event.ambr index 2a9b5540101..48f1d07e86f 100644 --- a/tests/components/balboa/snapshots/test_event.ambr +++ b/tests/components/balboa/snapshots/test_event.ambr @@ -41,6 +41,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/balboa/snapshots/test_fan.ambr b/tests/components/balboa/snapshots/test_fan.ambr index e4d619dc536..34a48e79872 100644 --- a/tests/components/balboa/snapshots/test_fan.ambr +++ b/tests/components/balboa/snapshots/test_fan.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump 1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/balboa/snapshots/test_light.ambr b/tests/components/balboa/snapshots/test_light.ambr index af4b4f973e7..02bdfd8457f 100644 --- a/tests/components/balboa/snapshots/test_light.ambr +++ b/tests/components/balboa/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/balboa/snapshots/test_select.ambr b/tests/components/balboa/snapshots/test_select.ambr index ae0aafa449e..ceee8096185 100644 --- a/tests/components/balboa/snapshots/test_select.ambr +++ b/tests/components/balboa/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature range', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/balboa/snapshots/test_switch.ambr b/tests/components/balboa/snapshots/test_switch.ambr index 886e07f64bf..f5002cdffe3 100644 --- a/tests/components/balboa/snapshots/test_switch.ambr +++ b/tests/components/balboa/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 2 enabled', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/balboa/snapshots/test_time.ambr b/tests/components/balboa/snapshots/test_time.ambr index 2d1f9c42e95..75d9fd92355 100644 --- a/tests/components/balboa/snapshots/test_time.ambr +++ b/tests/components/balboa/snapshots/test_time.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 1 end', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 1 start', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 2 end', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cycle 2 start', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/binary_sensor/test_device_condition.py b/tests/components/binary_sensor/test_device_condition.py index 254c5428806..1e11e64d542 100644 --- a/tests/components/binary_sensor/test_device_condition.py +++ b/tests/components/binary_sensor/test_device_condition.py @@ -26,11 +26,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/binary_sensor/test_device_trigger.py b/tests/components/binary_sensor/test_device_trigger.py index e9ad5d0a1e1..dfbf106dc91 100644 --- a/tests/components/binary_sensor/test_device_trigger.py +++ b/tests/components/binary_sensor/test_device_trigger.py @@ -26,11 +26,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/binary_sensor/test_trigger.py b/tests/components/binary_sensor/test_trigger.py index 8c08feb17b6..94a48557c7d 100644 --- a/tests/components/binary_sensor/test_trigger.py +++ b/tests/components/binary_sensor/test_trigger.py @@ -1,8 +1,6 @@ """Test binary sensor trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -16,7 +14,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -25,21 +23,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_binary_sensors(hass: HomeAssistant) -> tuple[list[str], list[str]]: """Create multiple binary sensor entities associated with different targets.""" @@ -66,7 +49,7 @@ async def test_binary_sensor_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("binary_sensor"), @@ -99,7 +82,7 @@ async def test_binary_sensor_state_attribute_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the binary sensor state trigger fires when any binary sensor state changes to a specific state.""" other_entity_ids = set(target_binary_sensors["included"]) - {entity_id} @@ -136,7 +119,7 @@ async def test_binary_sensor_state_attribute_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("binary_sensor"), @@ -169,7 +152,7 @@ async def test_binary_sensor_state_attribute_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the binary sensor state trigger fires when the first binary sensor state changes to a specific state.""" other_entity_ids = set(target_binary_sensors["included"]) - {entity_id} @@ -205,7 +188,7 @@ async def test_binary_sensor_state_attribute_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("binary_sensor"), @@ -238,7 +221,7 @@ async def test_binary_sensor_state_attribute_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the binary sensor state trigger fires when the last binary sensor state changes to a specific state.""" other_entity_ids = set(target_binary_sensors["included"]) - {entity_id} diff --git a/tests/components/blue_current/snapshots/test_button.ambr b/tests/components/blue_current/snapshots/test_button.ambr index 36a043630ea..8e447492342 100644 --- a/tests/components/blue_current/snapshots/test_button.ambr +++ b/tests/components/blue_current/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reboot', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge session', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bluemaestro/snapshots/test_sensor.ambr b/tests/components/bluemaestro/snapshots/test_sensor.ambr index 055ceb2731f..a081de9c6a6 100644 --- a/tests/components/bluemaestro/snapshots/test_sensor.ambr +++ b/tests/components/bluemaestro/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -237,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/blueprint/common.py b/tests/components/blueprint/common.py deleted file mode 100644 index 037aa38f6cb..00000000000 --- a/tests/components/blueprint/common.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Blueprints test helpers.""" - -from collections.abc import Generator -from unittest.mock import patch - - -def stub_blueprint_populate_fixture_helper() -> Generator[None]: - """Stub copying the blueprints to the config folder.""" - with patch( - "homeassistant.components.blueprint.models.DomainBlueprints.async_populate" - ): - yield diff --git a/tests/components/blueprint/conftest.py b/tests/components/blueprint/conftest.py deleted file mode 100644 index 21cc17ef1ba..00000000000 --- a/tests/components/blueprint/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Blueprints conftest.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/blueprint/test_websocket_api.py b/tests/components/blueprint/test_websocket_api.py index 8374054ca95..96a9323fda5 100644 --- a/tests/components/blueprint/test_websocket_api.py +++ b/tests/components/blueprint/test_websocket_api.py @@ -11,6 +11,7 @@ from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component from homeassistant.util.yaml import UndefinedSubstitution, parse_yaml +from tests.common import MockUser from tests.test_util.aiohttp import AiohttpClientMocker from tests.typing import WebSocketGenerator @@ -103,6 +104,51 @@ async def test_list_blueprints_non_existing_domain( assert blueprints == {} +@pytest.mark.parametrize( + "message", + [ + {"type": "blueprint/list", "domain": "automation"}, + {"type": "blueprint/import", "url": "https://example.com/blueprint.yaml"}, + { + "type": "blueprint/save", + "path": "test_save", + "yaml": "raw_data", + "domain": "automation", + }, + { + "type": "blueprint/delete", + "path": "test_delete", + "domain": "automation", + }, + { + "type": "blueprint/substitute", + "domain": "automation", + "path": "test_event_service.yaml", + "input": { + "trigger_event": "test_event", + "service_to_call": "test.automation", + "a_number": 5, + }, + }, + ], +) +async def test_blueprint_ws_command_requires_admin( + hass: HomeAssistant, + hass_ws_client: WebSocketGenerator, + hass_admin_user: MockUser, + message: dict[str, Any], +) -> None: + """Test that blueprint websocket commands require admin.""" + hass_admin_user.groups = [] # Remove admin privileges + client = await hass_ws_client(hass) + await client.send_json_auto_id(message) + + msg = await client.receive_json() + + assert not msg["success"] + assert msg["error"]["code"] == "unauthorized" + + async def test_import_blueprint( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, diff --git a/tests/components/bmw_connected_drive/snapshots/test_binary_sensor.ambr b/tests/components/bmw_connected_drive/snapshots/test_binary_sensor.ambr index 3a7cdd86be1..7290a7c7c98 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_binary_sensor.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Check control messages', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition-based services', 'options': dict({ }), 'original_device_class': , @@ -173,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection status', 'options': dict({ }), 'original_device_class': , @@ -222,6 +226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door lock state', 'options': dict({ }), 'original_device_class': , @@ -272,6 +277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lids', 'options': dict({ }), 'original_device_class': , @@ -328,6 +334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pre-entry climatization', 'options': dict({ }), 'original_device_class': None, @@ -376,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -427,6 +435,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -476,6 +485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Check control messages', 'options': dict({ }), 'original_device_class': , @@ -526,6 +536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition-based services', 'options': dict({ }), 'original_device_class': , @@ -586,6 +597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection status', 'options': dict({ }), 'original_device_class': , @@ -635,6 +647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door lock state', 'options': dict({ }), 'original_device_class': , @@ -685,6 +698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lids', 'options': dict({ }), 'original_device_class': , @@ -740,6 +754,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pre-entry climatization', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -842,6 +858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -891,6 +908,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Check control messages', 'options': dict({ }), 'original_device_class': , @@ -941,6 +959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition-based services', 'options': dict({ }), 'original_device_class': , @@ -1001,6 +1020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection status', 'options': dict({ }), 'original_device_class': , @@ -1050,6 +1070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door lock state', 'options': dict({ }), 'original_device_class': , @@ -1100,6 +1121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lids', 'options': dict({ }), 'original_device_class': , @@ -1156,6 +1178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pre-entry climatization', 'options': dict({ }), 'original_device_class': None, @@ -1204,6 +1227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -1258,6 +1282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Check control messages', 'options': dict({ }), 'original_device_class': , @@ -1309,6 +1334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition-based services', 'options': dict({ }), 'original_device_class': , @@ -1372,6 +1398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door lock state', 'options': dict({ }), 'original_device_class': , @@ -1422,6 +1449,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lids', 'options': dict({ }), 'original_device_class': , @@ -1477,6 +1505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/bmw_connected_drive/snapshots/test_button.ambr b/tests/components/bmw_connected_drive/snapshots/test_button.ambr index f8946f8c668..4955dd6ed8e 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_button.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Find vehicle', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound horn', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Deactivate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Find vehicle', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound horn', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Deactivate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Find vehicle', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound horn', 'options': dict({ }), 'original_device_class': None, @@ -692,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -740,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Deactivate air conditioning', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Find vehicle', 'options': dict({ }), 'original_device_class': None, @@ -836,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -884,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound horn', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bmw_connected_drive/snapshots/test_lock.ambr b/tests/components/bmw_connected_drive/snapshots/test_lock.ambr index 47eee9fdb15..72c6fb570cb 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_lock.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bmw_connected_drive/snapshots/test_number.ambr b/tests/components/bmw_connected_drive/snapshots/test_number.ambr index c86ed54197c..6a00c737599 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_number.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target SoC', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target SoC', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/bmw_connected_drive/snapshots/test_select.ambr b/tests/components/bmw_connected_drive/snapshots/test_select.ambr index 15334fc72b8..e3282b9599d 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_select.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging mode', 'options': dict({ }), 'original_device_class': None, @@ -95,6 +96,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC charging limit', 'options': dict({ }), 'original_device_class': None, @@ -165,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging mode', 'options': dict({ }), 'original_device_class': None, @@ -234,6 +237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC charging limit', 'options': dict({ }), 'original_device_class': None, @@ -304,6 +308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr b/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr index 2f7d2847ad6..d54fe87c4fd 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging end time', 'options': dict({ }), 'original_device_class': , @@ -122,6 +124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging start time', 'options': dict({ }), 'original_device_class': , @@ -186,6 +189,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -249,6 +253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging target', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -303,6 +308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -359,6 +365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining battery percent', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -415,6 +422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining fuel', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -471,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining fuel percent', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range electric', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range fuel', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -638,6 +649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -692,6 +704,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -745,6 +758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging end time', 'options': dict({ }), 'original_device_class': , @@ -794,6 +808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging start time', 'options': dict({ }), 'original_device_class': , @@ -858,6 +873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -921,6 +937,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging target', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -981,6 +998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate status', 'options': dict({ }), 'original_device_class': , @@ -1039,6 +1057,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1098,6 +1117,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1157,6 +1177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1216,6 +1237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1275,6 +1297,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1331,6 +1354,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1390,6 +1414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1449,6 +1474,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1508,6 +1534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1567,6 +1594,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining battery percent', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1623,6 +1651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range electric', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1679,6 +1708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1733,6 +1763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1786,6 +1817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging end time', 'options': dict({ }), 'original_device_class': , @@ -1835,6 +1867,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging start time', 'options': dict({ }), 'original_device_class': , @@ -1899,6 +1932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -1962,6 +1996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging target', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2022,6 +2057,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate status', 'options': dict({ }), 'original_device_class': , @@ -2080,6 +2116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2139,6 +2176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2198,6 +2236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2257,6 +2296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2316,6 +2356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2372,6 +2413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2431,6 +2473,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2490,6 +2533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2549,6 +2593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2608,6 +2653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining battery percent', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2664,6 +2710,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range electric', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2720,6 +2767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2782,6 +2830,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate status', 'options': dict({ }), 'original_device_class': , @@ -2840,6 +2889,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2899,6 +2949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2958,6 +3009,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3017,6 +3069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3076,6 +3129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3132,6 +3186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3191,6 +3246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3250,6 +3306,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right target pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3309,6 +3366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right tire pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3368,6 +3426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining fuel', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3424,6 +3483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining fuel percent', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3479,6 +3539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range fuel', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3535,6 +3596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/bmw_connected_drive/snapshots/test_switch.ambr b/tests/components/bmw_connected_drive/snapshots/test_switch.ambr index afd52e82d90..cafae0a3913 100644 --- a/tests/components/bmw_connected_drive/snapshots/test_switch.ambr +++ b/tests/components/bmw_connected_drive/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bosch_alarm/snapshots/test_alarm_control_panel.ambr b/tests/components/bosch_alarm/snapshots/test_alarm_control_panel.ambr index 54e012d72c3..d0ac464a2e2 100644 --- a/tests/components/bosch_alarm/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/bosch_alarm/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bosch_alarm/snapshots/test_binary_sensor.ambr b/tests/components/bosch_alarm/snapshots/test_binary_sensor.ambr index 2646a6affa7..a4330d58fb4 100644 --- a/tests/components/bosch_alarm/snapshots/test_binary_sensor.ambr +++ b/tests/components/bosch_alarm/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area ready to arm away', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area ready to arm home', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC failure', 'options': dict({ }), 'original_device_class': , @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -262,6 +267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery missing', 'options': dict({ }), 'original_device_class': , @@ -311,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CRC failure in panel configuration', 'options': dict({ }), 'original_device_class': , @@ -360,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Failure to call RPS since last RPS connection', 'options': dict({ }), 'original_device_class': None, @@ -408,6 +416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Log overflow', 'options': dict({ }), 'original_device_class': , @@ -457,6 +466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Log threshold reached', 'options': dict({ }), 'original_device_class': , @@ -506,6 +516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phone line failure', 'options': dict({ }), 'original_device_class': , @@ -555,6 +566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Point bus failure since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -604,6 +616,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -653,6 +666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDI failure since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -702,6 +716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code tamper since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -751,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -799,6 +815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -847,6 +864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -895,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -943,6 +962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -991,6 +1011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1039,6 +1060,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area ready to arm away', 'options': dict({ }), 'original_device_class': None, @@ -1087,6 +1109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area ready to arm home', 'options': dict({ }), 'original_device_class': None, @@ -1135,6 +1158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1183,6 +1207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC failure', 'options': dict({ }), 'original_device_class': , @@ -1232,6 +1257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1281,6 +1307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery missing', 'options': dict({ }), 'original_device_class': , @@ -1330,6 +1357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CRC failure in panel configuration', 'options': dict({ }), 'original_device_class': , @@ -1379,6 +1407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Failure to call RPS since last RPS connection', 'options': dict({ }), 'original_device_class': None, @@ -1427,6 +1456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Log overflow', 'options': dict({ }), 'original_device_class': , @@ -1476,6 +1506,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Log threshold reached', 'options': dict({ }), 'original_device_class': , @@ -1525,6 +1556,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phone line failure', 'options': dict({ }), 'original_device_class': , @@ -1574,6 +1606,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Point bus failure since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -1623,6 +1656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -1672,6 +1706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDI failure since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -1721,6 +1756,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code tamper since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -1770,6 +1806,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1818,6 +1855,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1866,6 +1904,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1914,6 +1953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1962,6 +2002,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2010,6 +2051,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2058,6 +2100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area ready to arm away', 'options': dict({ }), 'original_device_class': None, @@ -2106,6 +2149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area ready to arm home', 'options': dict({ }), 'original_device_class': None, @@ -2154,6 +2198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2202,6 +2247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC failure', 'options': dict({ }), 'original_device_class': , @@ -2251,6 +2297,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2300,6 +2347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery missing', 'options': dict({ }), 'original_device_class': , @@ -2349,6 +2397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CRC failure in panel configuration', 'options': dict({ }), 'original_device_class': , @@ -2398,6 +2447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Failure to call RPS since last RPS connection', 'options': dict({ }), 'original_device_class': None, @@ -2446,6 +2496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Log overflow', 'options': dict({ }), 'original_device_class': , @@ -2495,6 +2546,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Log threshold reached', 'options': dict({ }), 'original_device_class': , @@ -2544,6 +2596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phone line failure', 'options': dict({ }), 'original_device_class': , @@ -2593,6 +2646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Point bus failure since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -2642,6 +2696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -2691,6 +2746,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDI failure since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -2740,6 +2796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code tamper since last RPS connection', 'options': dict({ }), 'original_device_class': , @@ -2789,6 +2846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2837,6 +2895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2885,6 +2944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2933,6 +2993,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2981,6 +3042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3029,6 +3091,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bosch_alarm/snapshots/test_sensor.ambr b/tests/components/bosch_alarm/snapshots/test_sensor.ambr index c83f4b99cb1..19a7ec358cb 100644 --- a/tests/components/bosch_alarm/snapshots/test_sensor.ambr +++ b/tests/components/bosch_alarm/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burglary alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Faulting points', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fire alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -165,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burglary alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Faulting points', 'options': dict({ }), 'original_device_class': None, @@ -310,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fire alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -358,6 +365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -406,6 +414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burglary alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -454,6 +463,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Faulting points', 'options': dict({ }), 'original_device_class': None, @@ -503,6 +513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fire alarm issues', 'options': dict({ }), 'original_device_class': None, @@ -551,6 +562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas alarm issues', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bosch_alarm/snapshots/test_switch.ambr b/tests/components/bosch_alarm/snapshots/test_switch.ambr index 760ce7e2892..8f28e1c6bb1 100644 --- a/tests/components/bosch_alarm/snapshots/test_switch.ambr +++ b/tests/components/bosch_alarm/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Locked', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Momentarily unlocked', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Secured', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Locked', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Momentarily unlocked', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Secured', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Locked', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Momentarily unlocked', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Secured', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bring/snapshots/test_event.ambr b/tests/components/bring/snapshots/test_event.ambr index ceaef2bef87..53f714221c4 100644 --- a/tests/components/bring/snapshots/test_event.ambr +++ b/tests/components/bring/snapshots/test_event.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activities', 'options': dict({ }), 'original_device_class': None, @@ -111,6 +112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activities', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bring/snapshots/test_sensor.ambr b/tests/components/bring/snapshots/test_sensor.ambr index f3b37fd8b21..1f65c953540 100644 --- a/tests/components/bring/snapshots/test_sensor.ambr +++ b/tests/components/bring/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discount only', 'options': dict({ }), 'original_device_class': None, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'List access', 'options': dict({ }), 'original_device_class': , @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On occasion', 'options': dict({ }), 'original_device_class': None, @@ -201,6 +204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Region & language', 'options': dict({ }), 'original_device_class': , @@ -272,6 +276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Urgent', 'options': dict({ }), 'original_device_class': None, @@ -321,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discount only', 'options': dict({ }), 'original_device_class': None, @@ -376,6 +382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'List access', 'options': dict({ }), 'original_device_class': , @@ -430,6 +437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On occasion', 'options': dict({ }), 'original_device_class': None, @@ -502,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Region & language', 'options': dict({ }), 'original_device_class': , @@ -573,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Urgent', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bring/snapshots/test_todo.ambr b/tests/components/bring/snapshots/test_todo.ambr index bc65c6b020b..e0182729fc0 100644 --- a/tests/components/bring/snapshots/test_todo.ambr +++ b/tests/components/bring/snapshots/test_todo.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/brother/snapshots/test_sensor.ambr b/tests/components/brother/snapshots/test_sensor.ambr index b25d6a20a65..591b1a4be10 100644 --- a/tests/components/brother/snapshots/test_sensor.ambr +++ b/tests/components/brother/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'B/W pages', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Belt unit remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Black drum page counter', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Black drum remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Black drum remaining pages', 'options': dict({ }), 'original_device_class': None, @@ -282,6 +287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Black toner remaining', 'options': dict({ }), 'original_device_class': None, @@ -334,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Color pages', 'options': dict({ }), 'original_device_class': None, @@ -386,6 +393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cyan drum page counter', 'options': dict({ }), 'original_device_class': None, @@ -438,6 +446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cyan drum remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -490,6 +499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cyan drum remaining pages', 'options': dict({ }), 'original_device_class': None, @@ -542,6 +552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cyan toner remaining', 'options': dict({ }), 'original_device_class': None, @@ -594,6 +605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Drum page counter', 'options': dict({ }), 'original_device_class': None, @@ -646,6 +658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Drum remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -698,6 +711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Drum remaining pages', 'options': dict({ }), 'original_device_class': None, @@ -750,6 +764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Duplex unit page counter', 'options': dict({ }), 'original_device_class': None, @@ -802,6 +817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuser remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -852,6 +868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -903,6 +920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Magenta drum page counter', 'options': dict({ }), 'original_device_class': None, @@ -955,6 +973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Magenta drum remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -1007,6 +1026,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Magenta drum remaining pages', 'options': dict({ }), 'original_device_class': None, @@ -1059,6 +1079,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Magenta toner remaining', 'options': dict({ }), 'original_device_class': None, @@ -1111,6 +1132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Page counter', 'options': dict({ }), 'original_device_class': None, @@ -1163,6 +1185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PF Kit 1 remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -1213,6 +1236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -1263,6 +1287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yellow drum page counter', 'options': dict({ }), 'original_device_class': None, @@ -1315,6 +1340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yellow drum remaining lifetime', 'options': dict({ }), 'original_device_class': None, @@ -1367,6 +1393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yellow drum remaining pages', 'options': dict({ }), 'original_device_class': None, @@ -1419,6 +1446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yellow toner remaining', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bryant_evolution/snapshots/test_climate.ambr b/tests/components/bryant_evolution/snapshots/test_climate.ambr index 4b38e532139..7b80660f7af 100644 --- a/tests/components/bryant_evolution/snapshots/test_climate.ambr +++ b/tests/components/bryant_evolution/snapshots/test_climate.ambr @@ -35,6 +35,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bsblan/snapshots/test_climate.ambr b/tests/components/bsblan/snapshots/test_climate.ambr index 9efd1b79e29..676a029cdd5 100644 --- a/tests/components/bsblan/snapshots/test_climate.ambr +++ b/tests/components/bsblan/snapshots/test_climate.ambr @@ -32,6 +32,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -107,6 +108,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bsblan/snapshots/test_sensor.ambr b/tests/components/bsblan/snapshots/test_sensor.ambr index dc775330e60..24f6c662308 100644 --- a/tests/components/bsblan/snapshots/test_sensor.ambr +++ b/tests/components/bsblan/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/bsblan/snapshots/test_water_heater.ambr b/tests/components/bsblan/snapshots/test_water_heater.ambr index c848d03d37c..515fc692f6b 100644 --- a/tests/components/bsblan/snapshots/test_water_heater.ambr +++ b/tests/components/bsblan/snapshots/test_water_heater.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/bsblan/test_climate.py b/tests/components/bsblan/test_climate.py index a57d24c1dd5..cc7cbf0aea4 100644 --- a/tests/components/bsblan/test_climate.py +++ b/tests/components/bsblan/test_climate.py @@ -159,6 +159,30 @@ async def test_climate_hvac_mode_none_value( assert state.state == "unknown" +async def test_climate_hvac_mode_object_none( + hass: HomeAssistant, + mock_bsblan: AsyncMock, + mock_config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test climate entity when hvac_mode object itself is None.""" + await setup_with_selected_platforms(hass, mock_config_entry, [Platform.CLIMATE]) + + # Set hvac_mode to None (the object itself, not just the value) + mock_bsblan.state.return_value.hvac_mode = None + + freezer.tick(timedelta(minutes=1)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # State should be unknown when hvac_mode object is None + state = hass.states.get(ENTITY_ID) + assert state is not None + assert state.state == "unknown" + # preset_mode should be "none" when hvac_mode object is None + assert state.attributes["preset_mode"] == PRESET_NONE + + async def test_climate_hvac_mode_string_fallback( hass: HomeAssistant, mock_bsblan: AsyncMock, diff --git a/tests/components/button/test_trigger.py b/tests/components/button/test_trigger.py index ab328b1dedc..0c6c228fb08 100644 --- a/tests/components/button/test_trigger.py +++ b/tests/components/button/test_trigger.py @@ -1,8 +1,5 @@ """Test button trigger.""" -from collections.abc import Generator -from unittest.mock import patch - import pytest from homeassistant.const import ( @@ -14,7 +11,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, set_or_remove_state, @@ -22,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_buttons(hass: HomeAssistant) -> list[str]: """Create multiple button entities associated with different targets.""" @@ -57,7 +39,7 @@ async def test_button_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("button"), @@ -163,7 +145,7 @@ async def test_button_state_trigger_behavior_any( entity_id: str, entities_in_target: int, trigger: str, - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the button state trigger fires when any button state changes to a specific state.""" other_entity_ids = set(target_buttons) - {entity_id} diff --git a/tests/components/calendar/conftest.py b/tests/components/calendar/conftest.py index ed21f1336c8..2226d66a3bc 100644 --- a/tests/components/calendar/conftest.py +++ b/tests/components/calendar/conftest.py @@ -44,10 +44,16 @@ class MockCalendarEntity(CalendarEntity): _attr_has_entity_name = True - def __init__(self, name: str, events: list[CalendarEvent] | None = None) -> None: + def __init__( + self, + name: str, + events: list[CalendarEvent] | None = None, + unique_id: str | None = None, + ) -> None: """Initialize entity.""" self._attr_name = name.capitalize() self._events = events or [] + self._attr_unique_id = unique_id @property def event(self) -> CalendarEvent | None: @@ -182,6 +188,7 @@ def create_test_entities() -> list[MockCalendarEntity]: location="Future Location", ) ], + unique_id="calendar_1_id", ) entity1.async_get_events = AsyncMock(wraps=entity1.async_get_events) @@ -195,6 +202,7 @@ def create_test_entities() -> list[MockCalendarEntity]: summary="Current Event", ) ], + unique_id="calendar_2_id", ) entity2.async_get_events = AsyncMock(wraps=entity2.async_get_events) diff --git a/tests/components/calendar/test_trigger.py b/tests/components/calendar/test_trigger.py index b0d7944041d..8d4fcab37d6 100644 --- a/tests/components/calendar/test_trigger.py +++ b/tests/components/calendar/test_trigger.py @@ -11,6 +11,7 @@ from __future__ import annotations from collections.abc import AsyncIterator, Callable, Generator from contextlib import asynccontextmanager +from dataclasses import dataclass import datetime import logging from typing import Any @@ -21,19 +22,141 @@ from freezegun.api import FrozenDateTimeFactory import pytest from homeassistant.components import automation, calendar -from homeassistant.components.calendar.trigger import EVENT_END, EVENT_START -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF +from homeassistant.components.calendar.trigger import ( + CONF_OFFSET_TYPE, + EVENT_END, + EVENT_START, + OFFSET_TYPE_AFTER, + OFFSET_TYPE_BEFORE, +) +from homeassistant.const import ( + ATTR_AREA_ID, + ATTR_DEVICE_ID, + ATTR_ENTITY_ID, + ATTR_LABEL_ID, + CONF_OFFSET, + CONF_OPTIONS, + CONF_PLATFORM, + CONF_TARGET, + SERVICE_TURN_OFF, +) from homeassistant.core import HomeAssistant +from homeassistant.helpers import ( + area_registry as ar, + device_registry as dr, + entity_registry as er, + label_registry as lr, +) from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util from .conftest import MockCalendarEntity -from tests.common import MockConfigEntry, async_fire_time_changed, async_mock_service +from tests.common import ( + MockConfigEntry, + async_fire_time_changed, + async_mock_service, + mock_device_registry, +) _LOGGER = logging.getLogger(__name__) +@dataclass +class TriggerFormat: + """Abstraction for different trigger configuration formats.""" + + id: str + + def get_platform(self, event_type: str) -> str: + """Get the platform string for trigger payload assertions.""" + raise NotImplementedError + + def get_trigger_data( + self, entity_id: str, event_type: str, offset: datetime.timedelta | None = None + ) -> dict[str, Any]: + """Get the trigger configuration data.""" + raise NotImplementedError + + def get_expected_call_data( + self, entity_id: str, event_type: str, calendar_event: dict[str, Any] + ) -> dict[str, Any]: + """Get the expected call data for assertion.""" + return { + "platform": self.get_platform(event_type), + "event": event_type, + "entity_id": entity_id, + "calendar_event": calendar_event, + } + + +@dataclass +class LegacyTriggerFormat(TriggerFormat): + """Legacy trigger format using platform: calendar with entity_id and event.""" + + id: str = "legacy" + + def get_platform(self, event_type: str) -> str: + """Get the platform string for trigger payload assertions.""" + return calendar.DOMAIN + + def get_trigger_data( + self, entity_id: str, event_type: str, offset: datetime.timedelta | None = None + ) -> dict[str, Any]: + """Get the trigger configuration data.""" + trigger_data: dict[str, Any] = { + CONF_PLATFORM: calendar.DOMAIN, + "entity_id": entity_id, + "event": event_type, + } + if offset: + trigger_data[CONF_OFFSET] = offset + return trigger_data + + +@dataclass +class TargetTriggerFormat(TriggerFormat): + """Target trigger format using platform: calendar.event_started/ended with target.""" + + id: str = "target" + + def get_platform(self, event_type: str) -> str: + """Get the platform string for trigger payload assertions.""" + trigger_type = "event_started" if event_type == EVENT_START else "event_ended" + return f"{calendar.DOMAIN}.{trigger_type}" + + def get_trigger_data( + self, entity_id: str, event_type: str, offset: datetime.timedelta | None = None + ) -> dict[str, Any]: + """Get the trigger configuration data.""" + trigger_type = "event_started" if event_type == EVENT_START else "event_ended" + trigger_data: dict[str, Any] = { + CONF_PLATFORM: f"{calendar.DOMAIN}.{trigger_type}", + CONF_TARGET: {"entity_id": entity_id}, + } + if offset: + options: dict[str, Any] = {} + # Convert signed offset to offset + offset_type + if offset < datetime.timedelta(0): + options[CONF_OFFSET] = -offset + options[CONF_OFFSET_TYPE] = OFFSET_TYPE_BEFORE + else: + options[CONF_OFFSET] = offset + options[CONF_OFFSET_TYPE] = OFFSET_TYPE_AFTER + trigger_data[CONF_OPTIONS] = options + return trigger_data + + +TRIGGER_FORMATS = [LegacyTriggerFormat(), TargetTriggerFormat()] +TRIGGER_FORMAT_IDS = [fmt.id for fmt in TRIGGER_FORMATS] + + +@pytest.fixture(params=TRIGGER_FORMATS, ids=TRIGGER_FORMAT_IDS) +def trigger_format(request: pytest.FixtureRequest) -> TriggerFormat: + """Fixture providing both trigger formats for parameterized tests.""" + return request.param + + CALENDAR_ENTITY_ID = "calendar.calendar_2" TEST_AUTOMATION_ACTION = { @@ -41,6 +164,7 @@ TEST_AUTOMATION_ACTION = { "data": { "platform": "{{ trigger.platform }}", "event": "{{ trigger.event }}", + "entity_id": "{{ trigger.entity_id }}", "calendar_event": "{{ trigger.calendar_event }}", }, } @@ -51,6 +175,59 @@ TEST_AUTOMATION_ACTION = { TEST_TIME_ADVANCE_INTERVAL = datetime.timedelta(minutes=1) TEST_UPDATE_INTERVAL = datetime.timedelta(minutes=7) +TARGET_TEST_FIRST_START_CALL_DATA = [ + { + "platform": "calendar.event_started", + "event": "start", + "entity_id": "calendar.calendar_1", + "calendar_event": { + "start": "2022-04-19T11:00:00+00:00", + "end": "2022-04-19T11:30:00+00:00", + "summary": "Event on Calendar 1", + "all_day": False, + }, + } +] +TARGET_TEST_SECOND_START_CALL_DATA = [ + { + "platform": "calendar.event_started", + "event": "start", + "entity_id": "calendar.calendar_2", + "calendar_event": { + "start": "2022-04-19T11:15:00+00:00", + "end": "2022-04-19T11:45:00+00:00", + "summary": "Event on Calendar 2", + "all_day": False, + }, + } +] +TARGET_TEST_FIRST_END_CALL_DATA = [ + { + "platform": "calendar.event_ended", + "event": "end", + "entity_id": "calendar.calendar_1", + "calendar_event": { + "start": "2022-04-19T11:00:00+00:00", + "end": "2022-04-19T11:30:00+00:00", + "summary": "Event on Calendar 1", + "all_day": False, + }, + } +] +TARGET_TEST_SECOND_END_CALL_DATA = [ + { + "platform": "calendar.event_ended", + "event": "end", + "entity_id": "calendar.calendar_2", + "calendar_event": { + "start": "2022-04-19T11:15:00+00:00", + "end": "2022-04-19T11:45:00+00:00", + "summary": "Event on Calendar 2", + "all_day": False, + }, + } +] + class FakeSchedule: """Test fixture class for return events in a specific date range.""" @@ -110,18 +287,65 @@ async def mock_setup_platform( await hass.async_block_till_done() +@pytest.fixture +def target_calendars( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + area_registry: ar.AreaRegistry, + label_registry: lr.LabelRegistry, +): + """Associate calendar entities with different targets. + + Sets up the following target structure: + - area_both: An area containing both calendar entities + - label_calendar_1: A label assigned to calendar 1 only + - device_calendar_1: A device associated with calendar 1 + - device_calendar_2: A device associated with calendar 2 + - area_devices: An area containing both devices + """ + area_both = area_registry.async_get_or_create("area_both_calendars") + label_calendar_1 = label_registry.async_create("calendar_1_label") + label_on_devices = label_registry.async_create("label_on_devices") + + device_calendar_1 = dr.DeviceEntry( + id="device_calendar_1", labels=[label_on_devices.label_id] + ) + device_calendar_2 = dr.DeviceEntry( + id="device_calendar_2", labels=[label_on_devices.label_id] + ) + mock_device_registry( + hass, + { + device_calendar_1.id: device_calendar_1, + device_calendar_2.id: device_calendar_2, + }, + ) + + # Associate calendar entities with targets + entity_registry.async_update_entity( + "calendar.calendar_1", + area_id=area_both.id, + labels={label_calendar_1.label_id}, + device_id=device_calendar_1.id, + ) + entity_registry.async_update_entity( + "calendar.calendar_2", + area_id=area_both.id, + device_id=device_calendar_2.id, + ) + + @asynccontextmanager async def create_automation( - hass: HomeAssistant, event_type: str, offset=None + hass: HomeAssistant, + trigger_format: TriggerFormat, + event_type: str, + offset: datetime.timedelta | None = None, ) -> AsyncIterator[None]: - """Register an automation.""" - trigger_data = { - "platform": calendar.DOMAIN, - "entity_id": CALENDAR_ENTITY_ID, - "event": event_type, - } - if offset: - trigger_data["offset"] = offset + """Register an automation using the specified trigger format.""" + trigger_data = trigger_format.get_trigger_data( + CALENDAR_ENTITY_ID, event_type, offset + ) assert await async_setup_component( hass, automation.DOMAIN, @@ -173,13 +397,14 @@ async def test_event_start_trigger( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test the a calendar trigger based on start time.""" event_data = test_entity.create_event( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): assert len(calls_data()) == 0 await fake_schedule.fire_until( @@ -187,19 +412,17 @@ async def test_event_start_trigger( ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data + ) ] @pytest.mark.parametrize( - ("offset_str", "offset_delta"), + ("offset_delta"), [ - ("-01:00", datetime.timedelta(hours=-1)), - ("+01:00", datetime.timedelta(hours=1)), + datetime.timedelta(hours=-1), + datetime.timedelta(hours=1), ], ) async def test_event_start_trigger_with_offset( @@ -207,15 +430,17 @@ async def test_event_start_trigger_with_offset( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, - offset_str, - offset_delta, + trigger_format: TriggerFormat, + offset_delta: datetime.timedelta, ) -> None: """Test the a calendar trigger based on start time with an offset.""" event_data = test_entity.create_event( start=datetime.datetime.fromisoformat("2022-04-19 12:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 12:30:00+00:00"), ) - async with create_automation(hass, EVENT_START, offset=offset_str): + async with create_automation( + hass, trigger_format, EVENT_START, offset=offset_delta + ): # No calls yet await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:55:00+00:00") + offset_delta, @@ -227,11 +452,9 @@ async def test_event_start_trigger_with_offset( datetime.datetime.fromisoformat("2022-04-19 12:05:00+00:00") + offset_delta, ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data + ) ] @@ -240,13 +463,14 @@ async def test_event_end_trigger( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test the a calendar trigger based on end time.""" event_data = test_entity.create_event( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 12:00:00+00:00"), ) - async with create_automation(hass, EVENT_END): + async with create_automation(hass, trigger_format, EVENT_END): # Event started, nothing should fire yet await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:10:00+00:00") @@ -258,19 +482,17 @@ async def test_event_end_trigger( datetime.datetime.fromisoformat("2022-04-19 12:10:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_END, - "calendar_event": event_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_END, event_data + ) ] @pytest.mark.parametrize( - ("offset_str", "offset_delta"), + ("offset_delta"), [ - ("-01:00", datetime.timedelta(hours=-1)), - ("+01:00", datetime.timedelta(hours=1)), + datetime.timedelta(hours=-1), + datetime.timedelta(hours=1), ], ) async def test_event_end_trigger_with_offset( @@ -278,15 +500,15 @@ async def test_event_end_trigger_with_offset( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, - offset_str, - offset_delta, + trigger_format: TriggerFormat, + offset_delta: datetime.timedelta, ) -> None: """Test the a calendar trigger based on end time with an offset.""" event_data = test_entity.create_event( start=datetime.datetime.fromisoformat("2022-04-19 12:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 12:30:00+00:00"), ) - async with create_automation(hass, EVENT_END, offset=offset_str): + async with create_automation(hass, trigger_format, EVENT_END, offset=offset_delta): # No calls yet await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 12:05:00+00:00") + offset_delta, @@ -298,11 +520,9 @@ async def test_event_end_trigger_with_offset( datetime.datetime.fromisoformat("2022-04-19 12:35:00+00:00") + offset_delta, ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_END, - "calendar_event": event_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_END, event_data + ) ] @@ -310,10 +530,14 @@ async def test_calendar_trigger_with_no_events( hass: HomeAssistant, calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, + trigger_format: TriggerFormat, ) -> None: """Test a calendar trigger setup with no events.""" - async with create_automation(hass, EVENT_START), create_automation(hass, EVENT_END): + async with ( + create_automation(hass, trigger_format, EVENT_START), + create_automation(hass, trigger_format, EVENT_END), + ): # No calls, at arbitrary times await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00") @@ -326,6 +550,7 @@ async def test_multiple_start_events( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test that a trigger fires for multiple events.""" @@ -337,21 +562,17 @@ async def test_multiple_start_events( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data1, - }, - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data2, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data1 + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data2 + ), ] @@ -360,6 +581,7 @@ async def test_multiple_end_events( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test that a trigger fires for multiple events.""" @@ -371,22 +593,18 @@ async def test_multiple_end_events( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"), ) - async with create_automation(hass, EVENT_END): + async with create_automation(hass, trigger_format, EVENT_END): await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_END, - "calendar_event": event_data1, - }, - { - "platform": "calendar", - "event": EVENT_END, - "calendar_event": event_data2, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_END, event_data1 + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_END, event_data2 + ), ] @@ -395,6 +613,7 @@ async def test_multiple_events_sharing_start_time( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test that a trigger fires for every event sharing a start time.""" @@ -406,22 +625,18 @@ async def test_multiple_events_sharing_start_time( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:35:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data1, - }, - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data2, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data1 + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data2 + ), ] @@ -430,6 +645,7 @@ async def test_overlap_events( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test that a trigger fires for events that overlap.""" @@ -441,22 +657,18 @@ async def test_overlap_events( start=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:45:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:20:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data1, - }, - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data2, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data1 + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data2 + ), ] @@ -507,6 +719,7 @@ async def test_update_next_event( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test detection of a new event after initial trigger is setup.""" @@ -514,7 +727,7 @@ async def test_update_next_event( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): # No calls before event start await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 10:45:00+00:00") @@ -532,16 +745,12 @@ async def test_update_next_event( datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data2, - }, - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data1, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data2 + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data1 + ), ] @@ -550,6 +759,7 @@ async def test_update_missed( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, + trigger_format: TriggerFormat, ) -> None: """Test that new events are missed if they arrive outside the update interval.""" @@ -557,7 +767,7 @@ async def test_update_missed( start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): # Events are refreshed at t+TEST_UPDATE_INTERVAL minutes. A new event is # added, but the next update happens after the event is already over. await fake_schedule.fire_until( @@ -575,11 +785,9 @@ async def test_update_missed( datetime.datetime.fromisoformat("2022-04-19 11:05:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data1, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data1 + ), ] @@ -641,22 +849,21 @@ async def test_event_payload( fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, set_time_zone: None, + trigger_format: TriggerFormat, create_data, fire_time, payload_data, ) -> None: """Test the fields in the calendar event payload are set.""" test_entity.create_event(**create_data) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): assert len(calls_data()) == 0 await fake_schedule.fire_until(fire_time) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": payload_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, payload_data + ) ] @@ -666,6 +873,7 @@ async def test_trigger_timestamp_window_edge( fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, freezer: FrozenDateTimeFactory, + trigger_format: TriggerFormat, ) -> None: """Test that events in the edge of a scan are included.""" freezer.move_to("2022-04-19 11:00:00+00:00") @@ -675,18 +883,16 @@ async def test_trigger_timestamp_window_edge( start=datetime.datetime.fromisoformat("2022-04-19 11:14:00+00:00"), end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): assert len(calls_data()) == 0 await fake_schedule.fire_until( datetime.datetime.fromisoformat("2022-04-19 11:20:00+00:00") ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data + ) ] @@ -696,6 +902,7 @@ async def test_event_start_trigger_dst( fake_schedule: FakeSchedule, test_entity: MockCalendarEntity, freezer: FrozenDateTimeFactory, + trigger_format: TriggerFormat, ) -> None: """Test a calendar event trigger happening at the start of daylight savings time.""" await hass.config.async_set_time_zone("America/Los_Angeles") @@ -720,7 +927,7 @@ async def test_event_start_trigger_dst( start=datetime.datetime(2023, 3, 12, 3, 30, tzinfo=tzinfo), end=datetime.datetime(2023, 3, 12, 3, 45, tzinfo=tzinfo), ) - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): assert len(calls_data()) == 0 await fake_schedule.fire_until( @@ -728,21 +935,15 @@ async def test_event_start_trigger_dst( ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event1_data, - }, - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event2_data, - }, - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event3_data, - }, + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event1_data + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event2_data + ), + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event3_data + ), ] @@ -751,8 +952,8 @@ async def test_config_entry_reload( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entities: list[MockCalendarEntity], - setup_platform: None, config_entry: MockConfigEntry, + trigger_format: TriggerFormat, ) -> None: """Test the a calendar trigger after a config entry reload. @@ -761,7 +962,7 @@ async def test_config_entry_reload( the automation kept a reference to the specific entity which would be invalid after a config entry was reloaded. """ - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): assert len(calls_data()) == 0 assert await hass.config_entries.async_reload(config_entry.entry_id) @@ -778,11 +979,9 @@ async def test_config_entry_reload( ) assert calls_data() == [ - { - "platform": "calendar", - "event": EVENT_START, - "calendar_event": event_data, - } + trigger_format.get_expected_call_data( + CALENDAR_ENTITY_ID, EVENT_START, event_data + ) ] @@ -791,12 +990,12 @@ async def test_config_entry_unload( calls_data: Callable[[], list[dict[str, Any]]], fake_schedule: FakeSchedule, test_entities: list[MockCalendarEntity], - setup_platform: None, config_entry: MockConfigEntry, caplog: pytest.LogCaptureFixture, + trigger_format: TriggerFormat, ) -> None: """Test an automation that references a calendar entity that is unloaded.""" - async with create_automation(hass, EVENT_START): + async with create_automation(hass, trigger_format, EVENT_START): assert len(calls_data()) == 0 assert await hass.config_entries.async_unload(config_entry.entry_id) @@ -806,3 +1005,172 @@ async def test_config_entry_unload( ) assert "Entity does not exist calendar.calendar_2" in caplog.text + + +@pytest.mark.usefixtures("target_calendars") +@pytest.mark.parametrize( + ( + "trigger_target_conf", + "first_start_call_data", + "first_end_call_data", + "second_start_call_data", + "second_end_call_data", + ), + [ + ({}, [], [], [], []), + ( + {ATTR_ENTITY_ID: "calendar.calendar_2"}, + [], + [], + TARGET_TEST_SECOND_START_CALL_DATA, + TARGET_TEST_SECOND_END_CALL_DATA, + ), + ( + {ATTR_ENTITY_ID: ["calendar.calendar_1", "calendar.calendar_2"]}, + TARGET_TEST_FIRST_START_CALL_DATA, + TARGET_TEST_FIRST_END_CALL_DATA, + TARGET_TEST_SECOND_START_CALL_DATA, + TARGET_TEST_SECOND_END_CALL_DATA, + ), + ( + {ATTR_AREA_ID: "area_both_calendars"}, + TARGET_TEST_FIRST_START_CALL_DATA, + TARGET_TEST_FIRST_END_CALL_DATA, + TARGET_TEST_SECOND_START_CALL_DATA, + TARGET_TEST_SECOND_END_CALL_DATA, + ), + ( + {ATTR_LABEL_ID: "calendar_1_label"}, + TARGET_TEST_FIRST_START_CALL_DATA, + TARGET_TEST_FIRST_END_CALL_DATA, + [], + [], + ), + ( + {ATTR_DEVICE_ID: "device_calendar_1"}, + TARGET_TEST_FIRST_START_CALL_DATA, + TARGET_TEST_FIRST_END_CALL_DATA, + [], + [], + ), + ( + {ATTR_DEVICE_ID: "device_calendar_2"}, + [], + [], + TARGET_TEST_SECOND_START_CALL_DATA, + TARGET_TEST_SECOND_END_CALL_DATA, + ), + ( + {ATTR_LABEL_ID: "label_on_devices"}, + TARGET_TEST_FIRST_START_CALL_DATA, + TARGET_TEST_FIRST_END_CALL_DATA, + TARGET_TEST_SECOND_START_CALL_DATA, + TARGET_TEST_SECOND_END_CALL_DATA, + ), + ], +) +async def test_trigger_with_targets( + hass: HomeAssistant, + calls_data: Callable[[], list[dict[str, Any]]], + fake_schedule: FakeSchedule, + test_entities: list[MockCalendarEntity], + trigger_target_conf: dict[str, Any], + first_start_call_data: list[dict[str, Any]], + first_end_call_data: list[dict[str, Any]], + second_start_call_data: list[dict[str, Any]], + second_end_call_data: list[dict[str, Any]], +) -> None: + """Test that triggers fire for multiple calendar entities with target selector.""" + calendar_1 = test_entities[0] + calendar_2 = test_entities[1] + + calendar_1.create_event( + start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"), + end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"), + summary="Event on Calendar 1", + ) + calendar_2.create_event( + start=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"), + end=datetime.datetime.fromisoformat("2022-04-19 11:45:00+00:00"), + summary="Event on Calendar 2", + ) + + trigger_start = { + CONF_PLATFORM: "calendar.event_started", + CONF_TARGET: {**trigger_target_conf}, + } + trigger_end = { + CONF_PLATFORM: "calendar.event_ended", + CONF_TARGET: {**trigger_target_conf}, + } + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "alias": "start_trigger", + "trigger": trigger_start, + "action": TEST_AUTOMATION_ACTION, + "mode": "queued", + }, + { + "alias": "end_trigger", + "trigger": trigger_end, + "action": TEST_AUTOMATION_ACTION, + "mode": "queued", + }, + ] + }, + ) + await hass.async_block_till_done() + + assert len(calls_data()) == 0 + + # Advance past first event start + await fake_schedule.fire_until( + datetime.datetime.fromisoformat("2022-04-19 11:10:00+00:00") + ) + assert calls_data() == first_start_call_data + + # Advance past second event start + await fake_schedule.fire_until( + datetime.datetime.fromisoformat("2022-04-19 11:20:00+00:00") + ) + assert calls_data() == first_start_call_data + second_start_call_data + + # Advance past first event end + await fake_schedule.fire_until( + datetime.datetime.fromisoformat("2022-04-19 11:40:00+00:00") + ) + assert ( + calls_data() + == first_start_call_data + second_start_call_data + first_end_call_data + ) + + # Advance past second event end + await fake_schedule.fire_until( + datetime.datetime.fromisoformat("2022-04-19 11:50:00+00:00") + ) + assert ( + calls_data() + == first_start_call_data + + second_start_call_data + + first_end_call_data + + second_end_call_data + ) + + # Disable automations to cleanup lingering timers + await hass.services.async_call( + automation.DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "automation.start_trigger"}, + blocking=True, + ) + await hass.services.async_call( + automation.DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "automation.end_trigger"}, + blocking=True, + ) diff --git a/tests/components/cambridge_audio/snapshots/test_select.ambr b/tests/components/cambridge_audio/snapshots/test_select.ambr index 8e95966bc6a..99ced38246a 100644 --- a/tests/components/cambridge_audio/snapshots/test_select.ambr +++ b/tests/components/cambridge_audio/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Audio output', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Control Bus mode', 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display brightness', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/cambridge_audio/snapshots/test_switch.ambr b/tests/components/cambridge_audio/snapshots/test_switch.ambr index 63ac2b8a00c..3f00ac0b7a5 100644 --- a/tests/components/cambridge_audio/snapshots/test_switch.ambr +++ b/tests/components/cambridge_audio/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Early update', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pre-Amp', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ccm15/snapshots/test_climate.ambr b/tests/components/ccm15/snapshots/test_climate.ambr index d71672ce40c..53d3f1cd427 100644 --- a/tests/components/ccm15/snapshots/test_climate.ambr +++ b/tests/components/ccm15/snapshots/test_climate.ambr @@ -42,6 +42,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -99,6 +100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -236,6 +238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -293,6 +296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/chacon_dio/snapshots/test_cover.ambr b/tests/components/chacon_dio/snapshots/test_cover.ambr index 79d09957600..71091f5fc36 100644 --- a/tests/components/chacon_dio/snapshots/test_cover.ambr +++ b/tests/components/chacon_dio/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/chacon_dio/snapshots/test_switch.ambr b/tests/components/chacon_dio/snapshots/test_switch.ambr index ab8ef0fef36..5084219cd92 100644 --- a/tests/components/chacon_dio/snapshots/test_switch.ambr +++ b/tests/components/chacon_dio/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/climate/test_device_action.py b/tests/components/climate/test_device_action.py index 361aeaec867..a8165ae1b68 100644 --- a/tests/components/climate/test_device_action.py +++ b/tests/components/climate/test_device_action.py @@ -24,11 +24,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_action_types"), [ diff --git a/tests/components/climate/test_device_condition.py b/tests/components/climate/test_device_condition.py index 16595f57c6f..19c8addb5a8 100644 --- a/tests/components/climate/test_device_condition.py +++ b/tests/components/climate/test_device_condition.py @@ -20,11 +20,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_condition_types"), [ diff --git a/tests/components/climate/test_device_trigger.py b/tests/components/climate/test_device_trigger.py index 06072b88afe..51e14e49a26 100644 --- a/tests/components/climate/test_device_trigger.py +++ b/tests/components/climate/test_device_trigger.py @@ -26,11 +26,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/climate/test_trigger.py b/tests/components/climate/test_trigger.py index f98845708d1..0c26542b40d 100644 --- a/tests/components/climate/test_trigger.py +++ b/tests/components/climate/test_trigger.py @@ -1,9 +1,7 @@ """Test climate trigger.""" -from collections.abc import Generator from contextlib import AbstractContextManager, nullcontext as does_not_raise from typing import Any -from unittest.mock import patch import pytest import voluptuous as vol @@ -28,7 +26,7 @@ from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.helpers.trigger import async_validate_trigger_config from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, other_states, parametrize_numerical_attribute_changed_trigger_states, @@ -40,21 +38,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_climates(hass: HomeAssistant) -> list[str]: """Create multiple climate entities associated with different targets.""" @@ -91,7 +74,7 @@ async def test_climate_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger", "trigger_options", "expected_result"), [ @@ -147,7 +130,7 @@ async def test_climate_trigger_validation( ) -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("climate"), @@ -191,7 +174,7 @@ async def test_climate_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the climate state trigger fires when any climate state changes to a specific state.""" other_entity_ids = set(target_climates) - {entity_id} @@ -220,7 +203,7 @@ async def test_climate_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("climate"), @@ -286,7 +269,7 @@ async def test_climate_state_attribute_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the climate state trigger fires when any climate state changes to a specific state.""" other_entity_ids = set(target_climates) - {entity_id} @@ -315,7 +298,7 @@ async def test_climate_state_attribute_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("climate"), @@ -359,7 +342,7 @@ async def test_climate_state_trigger_behavior_first( entity_id: str, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the climate state trigger fires when the first climate changes to a specific state.""" other_entity_ids = set(target_climates) - {entity_id} @@ -389,7 +372,7 @@ async def test_climate_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("climate"), @@ -471,7 +454,7 @@ async def test_climate_state_attribute_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("climate"), @@ -515,7 +498,7 @@ async def test_climate_state_trigger_behavior_last( entity_id: str, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the climate state trigger fires when the last climate changes to a specific state.""" other_entity_ids = set(target_climates) - {entity_id} @@ -544,7 +527,7 @@ async def test_climate_state_trigger_behavior_last( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("climate"), diff --git a/tests/components/cloud/conftest.py b/tests/components/cloud/conftest.py index 3b802d0af63..a1bcd8095e2 100644 --- a/tests/components/cloud/conftest.py +++ b/tests/components/cloud/conftest.py @@ -245,6 +245,7 @@ async def cloud_prefs(hass: HomeAssistant) -> CloudPreferences: async def mock_cloud_setup(hass: HomeAssistant) -> None: """Set up the cloud.""" await mock_cloud(hass) + await hass.async_block_till_done() @pytest.fixture diff --git a/tests/components/cloud/test_http_api.py b/tests/components/cloud/test_http_api.py index f2844264ef0..eaaf42bc9bd 100644 --- a/tests/components/cloud/test_http_api.py +++ b/tests/components/cloud/test_http_api.py @@ -130,7 +130,6 @@ async def setup_cloud_fixture(hass: HomeAssistant, cloud: MagicMock) -> None: "relayer_server": "relayer", "acme_server": "cert-server", "api_server": "api-test.example.com", - "accounts_server": "api-test.hass.io", "google_actions": {"filter": {"include_domains": "light"}}, "alexa": { "filter": {"include_entities": ["light.kitchen", "switch.ac"]} diff --git a/tests/components/cloud/test_init.py b/tests/components/cloud/test_init.py index 71ff04d9f3a..92d9660016c 100644 --- a/tests/components/cloud/test_init.py +++ b/tests/components/cloud/test_init.py @@ -45,7 +45,6 @@ async def test_constructor_loads_info_from_config(hass: HomeAssistant) -> None: "region": "test-region", "api_server": "test-api-server", "relayer_server": "test-relayer-server", - "accounts_server": "test-acounts-server", "acme_server": "test-acme-server", "remotestate_server": "test-remotestate-server", "discovery_service_actions": { @@ -63,7 +62,6 @@ async def test_constructor_loads_info_from_config(hass: HomeAssistant) -> None: assert cl.region == "test-region" assert cl.relayer_server == "test-relayer-server" assert cl.iot.ws_server_url == "wss://test-relayer-server/websocket" - assert cl.accounts_server == "test-acounts-server" assert cl.acme_server == "test-acme-server" assert cl.api_server == "test-api-server" assert cl.remotestate_server == "test-remotestate-server" diff --git a/tests/components/cloud/test_repairs.py b/tests/components/cloud/test_repairs.py index 0377ee81dba..48e807b1598 100644 --- a/tests/components/cloud/test_repairs.py +++ b/tests/components/cloud/test_repairs.py @@ -48,7 +48,7 @@ async def test_create_repair_issues_at_startup_if_logged_in( ) -> None: """Test that we create repair issue at startup if we are logged in.""" aioclient_mock.get( - "https://accounts.nabucasa.com/payments/subscription_info", + "https://api.nabucasa.com/account/payments/subscription_info", json={"provider": "legacy"}, ) @@ -88,11 +88,11 @@ async def test_legacy_subscription_repair_flow( ) -> None: """Test desired flow of the fix flow for legacy subscription.""" aioclient_mock.get( - "https://accounts.nabucasa.com/payments/subscription_info", + "https://api.nabucasa.com/account/payments/subscription_info", json={"provider": None}, ) aioclient_mock.post( - "https://accounts.nabucasa.com/payments/migrate_paypal_agreement", + "https://api.nabucasa.com/account/payments/migrate_paypal_agreement", json={"url": "https://paypal.com"}, ) diff --git a/tests/components/cloud/test_subscription.py b/tests/components/cloud/test_subscription.py index 45c199421d6..2a8fb0eb5ff 100644 --- a/tests/components/cloud/test_subscription.py +++ b/tests/components/cloud/test_subscription.py @@ -20,7 +20,6 @@ from tests.test_util.aiohttp import AiohttpClientMocker async def mocked_cloud_object(hass: HomeAssistant) -> Cloud: """Mock cloud object.""" return Mock( - accounts_server="accounts.nabucasa.com", auth=Mock(async_check_token=AsyncMock()), websession=async_get_clientsession(hass), payments=Mock( diff --git a/tests/components/cloud/test_tts.py b/tests/components/cloud/test_tts.py index f830cb27259..ff7915ceee5 100644 --- a/tests/components/cloud/test_tts.py +++ b/tests/components/cloud/test_tts.py @@ -345,10 +345,10 @@ async def test_get_tts_audio_logged_out( @pytest.mark.parametrize( - ("mock_process_tts_side_effect"), + "mock_process_tts_side_effect", [ - (None,), - (VoiceError("Boom!"),), + None, + VoiceError("Boom!"), ], ) async def test_tts_entity( diff --git a/tests/components/co2signal/snapshots/test_sensor.ambr b/tests/components/co2signal/snapshots/test_sensor.ambr index 03f6123ec7c..a96534eaf5e 100644 --- a/tests/components/co2signal/snapshots/test_sensor.ambr +++ b/tests/components/co2signal/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CO2 intensity', 'options': dict({ }), 'original_device_class': None, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid fossil fuel percentage', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/comelit/snapshots/test_climate.ambr b/tests/components/comelit/snapshots/test_climate.ambr index c55836793f7..13363c80378 100644 --- a/tests/components/comelit/snapshots/test_climate.ambr +++ b/tests/components/comelit/snapshots/test_climate.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/comelit/snapshots/test_cover.ambr b/tests/components/comelit/snapshots/test_cover.ambr index a0575a19d2b..d4bc6683b20 100644 --- a/tests/components/comelit/snapshots/test_cover.ambr +++ b/tests/components/comelit/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/comelit/snapshots/test_humidifier.ambr b/tests/components/comelit/snapshots/test_humidifier.ambr index 587bc8513f2..4d47e1046f3 100644 --- a/tests/components/comelit/snapshots/test_humidifier.ambr +++ b/tests/components/comelit/snapshots/test_humidifier.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dehumidifier', 'options': dict({ }), 'original_device_class': , @@ -94,6 +95,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidifier', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/comelit/snapshots/test_light.ambr b/tests/components/comelit/snapshots/test_light.ambr index 734ce177673..7e53f334da4 100644 --- a/tests/components/comelit/snapshots/test_light.ambr +++ b/tests/components/comelit/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/comelit/snapshots/test_sensor.ambr b/tests/components/comelit/snapshots/test_sensor.ambr index 602b9a9cad3..cecfd97dfec 100644 --- a/tests/components/comelit/snapshots/test_sensor.ambr +++ b/tests/components/comelit/snapshots/test_sensor.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/comelit/snapshots/test_switch.ambr b/tests/components/comelit/snapshots/test_switch.ambr index d41394ed245..8c47f2a31a5 100644 --- a/tests/components/comelit/snapshots/test_switch.ambr +++ b/tests/components/comelit/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/config/test_automation.py b/tests/components/config/test_automation.py index b20b0fb5699..f05ee3b1fd2 100644 --- a/tests/components/config/test_automation.py +++ b/tests/components/config/test_automation.py @@ -18,16 +18,10 @@ from homeassistant.util import yaml as yaml_util from tests.typing import ClientSessionGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture async def setup_automation( hass: HomeAssistant, automation_config: dict[str, Any], - stub_blueprint_populate: None, ) -> None: """Set up automation integration.""" assert await async_setup_component( diff --git a/tests/components/config/test_device_registry.py b/tests/components/config/test_device_registry.py index 8a4e1ef234f..b9b04bb396c 100644 --- a/tests/components/config/test_device_registry.py +++ b/tests/components/config/test_device_registry.py @@ -17,11 +17,6 @@ from tests.common import MockConfigEntry, MockModule, mock_integration from tests.typing import MockHAClientWebSocket, WebSocketGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(name="client") async def client_fixture( hass: HomeAssistant, hass_ws_client: WebSocketGenerator diff --git a/tests/components/config/test_entity_registry.py b/tests/components/config/test_entity_registry.py index b6daf7027a6..6ae83a7c041 100644 --- a/tests/components/config/test_entity_registry.py +++ b/tests/components/config/test_entity_registry.py @@ -1350,19 +1350,18 @@ async def test_get_automatic_entity_ids( entity_id="test_domain.test_1", unique_id="uniq1", platform="test_domain", + object_id_base="test_1", ), "test_domain.test_2": RegistryEntryWithDefaults( entity_id="test_domain.test_2", unique_id="uniq2", platform="test_domain", - suggested_object_id="collision", ), "test_domain.test_3": RegistryEntryWithDefaults( entity_id="test_domain.test_3", name="Name by User 3", unique_id="uniq3", platform="test_domain", - suggested_object_id="suggested_3", ), "test_domain.test_4": RegistryEntryWithDefaults( entity_id="test_domain.test_4", @@ -1385,13 +1384,11 @@ async def test_get_automatic_entity_ids( entity_id="test_domain.test_7", unique_id="uniq7", platform="test_domain", - suggested_object_id="test_7", ), "test_domain.not_unique": RegistryEntryWithDefaults( entity_id="test_domain.not_unique", unique_id="not_unique_1", platform="test_domain", - suggested_object_id="not_unique", ), "test_domain.not_unique_2": RegistryEntryWithDefaults( entity_id="test_domain.not_unique_2", @@ -1403,7 +1400,6 @@ async def test_get_automatic_entity_ids( entity_id="test_domain.not_unique_3", unique_id="not_unique_3", platform="test_domain", - suggested_object_id="not_unique", ), "test_domain.also_not_unique_changed_1": RegistryEntryWithDefaults( entity_id="test_domain.also_not_unique_changed_1", @@ -1425,15 +1421,25 @@ async def test_get_automatic_entity_ids( component = EntityComponent(_LOGGER, DOMAIN, hass) await component.async_setup({}) - entity2 = MockEntity(unique_id="uniq2", name="Entity Name 2") - entity3 = MockEntity(unique_id="uniq3", name="Entity Name 3") + entity2 = MockEntity(unique_id="uniq2", entity_id="test_domain.collision") + entity3 = MockEntity( + unique_id="uniq3", name="Entity Name 3", entity_id="test_domain.suggested_3" + ) entity4 = MockEntity(unique_id="uniq4", name="Entity Name 4") entity5 = MockEntity(unique_id="uniq5", name="Entity Name 5") entity6 = MockEntity(unique_id="uniq6", name="Entity Name 6") - entity7 = MockEntity(unique_id="uniq7", name="Entity Name 7") - entity8 = MockEntity(unique_id="not_unique_1", name="Entity Name 8") + entity7 = MockEntity( + unique_id="uniq7", name="Entity Name 7", entity_id="test_domain.test_7" + ) + entity8 = MockEntity( + unique_id="not_unique_1", + name="Entity Name 8", + entity_id="test_domain.not_unique", + ) entity9 = MockEntity(unique_id="not_unique_2", name="Entity Name 9") - entity10 = MockEntity(unique_id="not_unique_3", name="Not unique") + entity10 = MockEntity( + unique_id="not_unique_3", name="Not unique", entity_id="test_domain.not_unique" + ) entity11 = MockEntity(unique_id="also_not_unique_1", name="Also not unique") entity12 = MockEntity(unique_id="also_not_unique_2", name="Also not unique") await component.async_add_entities( @@ -1477,8 +1483,9 @@ async def test_get_automatic_entity_ids( assert msg["success"] assert msg["result"] == { - # No entity object for test_domain.test_1 - "test_domain.test_1": None, + # No entity object for test_domain.test_1, + # but still works thanks to stored object_id_base + "test_domain.test_1": "test_domain.test_1", # The suggested_object_id is taken, fall back to suggested_object_id + _2 "test_domain.test_2": "test_domain.collision_2", # name set by user has higher priority than suggested_object_id or entity diff --git a/tests/components/config/test_script.py b/tests/components/config/test_script.py index 10d453b17f1..c5e4585af89 100644 --- a/tests/components/config/test_script.py +++ b/tests/components/config/test_script.py @@ -18,11 +18,6 @@ from homeassistant.util import yaml as yaml_util from tests.typing import ClientSessionGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) async def setup_script(hass: HomeAssistant, script_config: dict[str, Any]) -> None: """Set up script integration.""" diff --git a/tests/components/conftest.py b/tests/components/conftest.py index 7dff435dc9b..5dff1565ac7 100644 --- a/tests/components/conftest.py +++ b/tests/components/conftest.py @@ -108,17 +108,6 @@ def entity_registry_enabled_by_default() -> Generator[None]: yield -# Blueprint test fixtures -@pytest.fixture(name="stub_blueprint_populate") -def stub_blueprint_populate_fixture() -> Generator[None]: - """Stub copying the blueprints to the config folder.""" - from .blueprint.common import ( # noqa: PLC0415 - stub_blueprint_populate_fixture_helper, - ) - - yield from stub_blueprint_populate_fixture_helper() - - # TTS test fixtures @pytest.fixture(name="mock_tts_get_cache_files") def mock_tts_get_cache_files_fixture() -> Generator[MagicMock]: @@ -823,6 +812,9 @@ async def _check_config_flow_result_translations( integration = flow.handler issue_id = flow.issue_id issue = ir.async_get(flow.hass).async_get_issue(integration, issue_id) + if issue is None: + # Issue was deleted mid-flow (e.g., config entry removed), skip check + return key_prefix = f"{issue.translation_key}.fix_flow." description_placeholders = { # Both are used in issue translations, and description_placeholders @@ -1128,3 +1120,13 @@ async def check_translations( for description in translation_errors.values(): if description != "used": pytest.fail(description) + + +@pytest.fixture(name="enable_labs_preview_features") +def enable_labs_preview_features() -> Generator[None]: + """Enable labs preview features.""" + with patch( + "homeassistant.components.labs.async_is_preview_feature_enabled", + return_value=True, + ): + yield diff --git a/tests/components/control4/snapshots/test_climate.ambr b/tests/components/control4/snapshots/test_climate.ambr index d961babf59f..dc5d6c30edb 100644 --- a/tests/components/control4/snapshots/test_climate.ambr +++ b/tests/components/control4/snapshots/test_climate.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Residential Thermostat V2', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/control4/snapshots/test_media_player.ambr b/tests/components/control4/snapshots/test_media_player.ambr index 63ea93b7859..e89924b8470 100644 --- a/tests/components/control4/snapshots/test_media_player.ambr +++ b/tests/components/control4/snapshots/test_media_player.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/cookidoo/snapshots/test_button.ambr b/tests/components/cookidoo/snapshots/test_button.ambr index 43244132ae2..6f155d000c9 100644 --- a/tests/components/cookidoo/snapshots/test_button.ambr +++ b/tests/components/cookidoo/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clear shopping list and additional purchases', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/cookidoo/snapshots/test_calendar.ambr b/tests/components/cookidoo/snapshots/test_calendar.ambr index 6d1dd2bb70b..c76e8cc67dc 100644 --- a/tests/components/cookidoo/snapshots/test_calendar.ambr +++ b/tests/components/cookidoo/snapshots/test_calendar.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meal plan', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/cookidoo/snapshots/test_sensor.ambr b/tests/components/cookidoo/snapshots/test_sensor.ambr index 6b311cfea86..1c884c6cba4 100644 --- a/tests/components/cookidoo/snapshots/test_sensor.ambr +++ b/tests/components/cookidoo/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscription', 'options': dict({ }), 'original_device_class': , @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscription expiration date', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/cookidoo/snapshots/test_todo.ambr b/tests/components/cookidoo/snapshots/test_todo.ambr index 620d3c55db7..02f66cb8cf7 100644 --- a/tests/components/cookidoo/snapshots/test_todo.ambr +++ b/tests/components/cookidoo/snapshots/test_todo.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Additional purchases', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Shopping list', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/cover/test_device_action.py b/tests/components/cover/test_device_action.py index 438e5de751d..435711db8fe 100644 --- a/tests/components/cover/test_device_action.py +++ b/tests/components/cover/test_device_action.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_action_types"), [ diff --git a/tests/components/cover/test_device_condition.py b/tests/components/cover/test_device_condition.py index 5bd02120585..c8539f8c571 100644 --- a/tests/components/cover/test_device_condition.py +++ b/tests/components/cover/test_device_condition.py @@ -22,11 +22,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_condition_types"), [ diff --git a/tests/components/cover/test_device_trigger.py b/tests/components/cover/test_device_trigger.py index 1a6b50b2935..5a877741fff 100644 --- a/tests/components/cover/test_device_trigger.py +++ b/tests/components/cover/test_device_trigger.py @@ -26,11 +26,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_trigger_types"), [ diff --git a/tests/components/cync/snapshots/test_light.ambr b/tests/components/cync/snapshots/test_light.ambr index fbe56bb1c75..dbf8773fe7b 100644 --- a/tests/components/cync/snapshots/test_light.ambr +++ b/tests/components/cync/snapshots/test_light.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -112,6 +113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -195,6 +197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deako/snapshots/test_light.ambr b/tests/components/deako/snapshots/test_light.ambr index bed3bc366e8..b110ead08e4 100644 --- a/tests/components/deako/snapshots/test_light.ambr +++ b/tests/components/deako/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -139,6 +141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_alarm_control_panel.ambr b/tests/components/deconz/snapshots/test_alarm_control_panel.ambr index 95c5cada755..5b6828b2e9c 100644 --- a/tests/components/deconz/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/deconz/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keypad', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_binary_sensor.ambr b/tests/components/deconz/snapshots/test_binary_sensor.ambr index 6fb1140ec6f..f31a9af8082 100644 --- a/tests/components/deconz/snapshots/test_binary_sensor.ambr +++ b/tests/components/deconz/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm 10', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cave CO', 'options': dict({ }), 'original_device_class': , @@ -121,6 +123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cave CO Low Battery', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cave CO Tampered', 'options': dict({ }), 'original_device_class': , @@ -219,6 +223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor', 'options': dict({ }), 'original_device_class': , @@ -271,6 +276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor Low Battery', 'options': dict({ }), 'original_device_class': , @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor Tampered', 'options': dict({ }), 'original_device_class': , @@ -369,6 +376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'sensor_kitchen_smoke', 'options': dict({ }), 'original_device_class': , @@ -419,6 +427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'sensor_kitchen_smoke Test Mode', 'options': dict({ }), 'original_device_class': , @@ -468,6 +477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'sensor_kitchen_smoke', 'options': dict({ }), 'original_device_class': , @@ -518,6 +528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'sensor_kitchen_smoke Test Mode', 'options': dict({ }), 'original_device_class': , @@ -567,6 +578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen Switch', 'options': dict({ }), 'original_device_class': None, @@ -616,6 +628,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Back Door', 'options': dict({ }), 'original_device_class': , @@ -667,6 +680,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion sensor 4', 'options': dict({ }), 'original_device_class': , @@ -718,6 +732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'water2', 'options': dict({ }), 'original_device_class': , @@ -769,6 +784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'water2 Low Battery', 'options': dict({ }), 'original_device_class': , @@ -818,6 +834,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'water2 Tampered', 'options': dict({ }), 'original_device_class': , @@ -867,6 +884,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vibration 1', 'options': dict({ }), 'original_device_class': , @@ -925,6 +943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor', 'options': dict({ }), 'original_device_class': , @@ -977,6 +996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor Low Battery', 'options': dict({ }), 'original_device_class': , @@ -1026,6 +1046,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor Tampered', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/deconz/snapshots/test_button.ambr b/tests/components/deconz/snapshots/test_button.ambr index 237b0e1e50f..ca743807b1b 100644 --- a/tests/components/deconz/snapshots/test_button.ambr +++ b/tests/components/deconz/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scene Store Current Scene', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Reset Presence', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/deconz/snapshots/test_climate.ambr b/tests/components/deconz/snapshots/test_climate.ambr index cdae69abbcb..f2b7c242b37 100644 --- a/tests/components/deconz/snapshots/test_climate.ambr +++ b/tests/components/deconz/snapshots/test_climate.ambr @@ -38,6 +38,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zen-01', 'options': dict({ }), 'original_device_class': None, @@ -127,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zen-01', 'options': dict({ }), 'original_device_class': None, @@ -225,6 +227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zen-01', 'options': dict({ }), 'original_device_class': None, @@ -314,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat', 'options': dict({ }), 'original_device_class': None, @@ -382,6 +386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CLIP thermostat', 'options': dict({ }), 'original_device_class': None, @@ -449,6 +454,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat', 'options': dict({ }), 'original_device_class': None, @@ -517,6 +523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'thermostat', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_cover.ambr b/tests/components/deconz/snapshots/test_cover.ambr index 15e51b8443f..b893ff71fd3 100644 --- a/tests/components/deconz/snapshots/test_cover.ambr +++ b/tests/components/deconz/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window covering device', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vent', 'options': dict({ }), 'original_device_class': , @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Covering device', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/deconz/snapshots/test_fan.ambr b/tests/components/deconz/snapshots/test_fan.ambr index d8d6f7703f2..46f78f1b2e9 100644 --- a/tests/components/deconz/snapshots/test_fan.ambr +++ b/tests/components/deconz/snapshots/test_fan.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ceiling fan', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_light.ambr b/tests/components/deconz/snapshots/test_light.ambr index 39ce5e46236..ba3c678d439 100644 --- a/tests/components/deconz/snapshots/test_light.ambr +++ b/tests/components/deconz/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimmable light', 'options': dict({ }), 'original_device_class': None, @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -178,6 +180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RGB light', 'options': dict({ }), 'original_device_class': None, @@ -258,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tunable white light', 'options': dict({ }), 'original_device_class': None, @@ -336,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimmable light', 'options': dict({ }), 'original_device_class': None, @@ -403,6 +408,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -490,6 +496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RGB light', 'options': dict({ }), 'original_device_class': None, @@ -570,6 +577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tunable white light', 'options': dict({ }), 'original_device_class': None, @@ -648,6 +656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimmable light', 'options': dict({ }), 'original_device_class': None, @@ -715,6 +724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -802,6 +812,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RGB light', 'options': dict({ }), 'original_device_class': None, @@ -882,6 +893,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tunable white light', 'options': dict({ }), 'original_device_class': None, @@ -969,6 +981,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hue Go', 'options': dict({ }), 'original_device_class': None, @@ -1062,6 +1075,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hue Ensis', 'options': dict({ }), 'original_device_class': None, @@ -1164,6 +1178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LIDL xmas light', 'options': dict({ }), 'original_device_class': None, @@ -1259,6 +1274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hue White Ambiance', 'options': dict({ }), 'original_device_class': None, @@ -1337,6 +1353,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hue Filament', 'options': dict({ }), 'original_device_class': None, @@ -1396,6 +1413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Simple Light', 'options': dict({ }), 'original_device_class': None, @@ -1468,6 +1486,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gradient light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_number.ambr b/tests/components/deconz/snapshots/test_number.ambr index d264740e4c2..7723487ccc1 100644 --- a/tests/components/deconz/snapshots/test_number.ambr +++ b/tests/components/deconz/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor Delay', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence sensor Duration', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_scene.ambr b/tests/components/deconz/snapshots/test_scene.ambr index 4c04c6661d5..297bacce571 100644 --- a/tests/components/deconz/snapshots/test_scene.ambr +++ b/tests/components/deconz/snapshots/test_scene.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scene', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_select.ambr b/tests/components/deconz/snapshots/test_select.ambr index 5b8dc9509a7..27b05bbea4a 100644 --- a/tests/components/deconz/snapshots/test_select.ambr +++ b/tests/components/deconz/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Device Mode', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Trigger Distance', 'options': dict({ }), 'original_device_class': None, @@ -200,6 +203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Device Mode', 'options': dict({ }), 'original_device_class': None, @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -317,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Trigger Distance', 'options': dict({ }), 'original_device_class': None, @@ -375,6 +381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Device Mode', 'options': dict({ }), 'original_device_class': None, @@ -433,6 +440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -492,6 +500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aqara FP1 Trigger Distance', 'options': dict({ }), 'original_device_class': None, @@ -555,6 +564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IKEA Starkvind Fan Mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/deconz/snapshots/test_sensor.ambr b/tests/components/deconz/snapshots/test_sensor.ambr index 4a6bc43043b..87e5d437133 100644 --- a/tests/components/deconz/snapshots/test_sensor.ambr +++ b/tests/components/deconz/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CLIP Flur', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CLIP light level sensor', 'options': dict({ }), 'original_device_class': , @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light level sensor', 'options': dict({ }), 'original_device_class': , @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light level sensor Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -234,6 +238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BOSCH Air quality sensor', 'options': dict({ }), 'original_device_class': None, @@ -284,6 +289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BOSCH Air quality sensor PPB', 'options': dict({ }), 'original_device_class': None, @@ -334,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BOSCH Air quality sensor', 'options': dict({ }), 'original_device_class': None, @@ -384,6 +391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BOSCH Air quality sensor PPB', 'options': dict({ }), 'original_device_class': None, @@ -434,6 +442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FSM_STATE Motion stair', 'options': dict({ }), 'original_device_class': None, @@ -485,6 +494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mi temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -542,6 +552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mi temperature 1 Battery', 'options': dict({ }), 'original_device_class': , @@ -596,6 +607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soil Sensor', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -652,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soil Sensor Battery', 'options': dict({ }), 'original_device_class': , @@ -706,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion sensor 4', 'options': dict({ }), 'original_device_class': , @@ -762,6 +776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion sensor 4 Battery', 'options': dict({ }), 'original_device_class': , @@ -818,6 +833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'STARKVIND AirPurifier PM25', 'options': dict({ }), 'original_device_class': , @@ -871,6 +887,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power 16', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -930,6 +947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mi temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -987,6 +1005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mi temperature 1 Battery', 'options': dict({ }), 'original_device_class': , @@ -1041,6 +1060,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mi temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1098,6 +1118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mi temperature 1 Battery', 'options': dict({ }), 'original_device_class': , @@ -1150,6 +1171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'eTRV Séjour', 'options': dict({ }), 'original_device_class': , @@ -1201,6 +1223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'eTRV Séjour Battery', 'options': dict({ }), 'original_device_class': , @@ -1255,6 +1278,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm 10 Battery', 'options': dict({ }), 'original_device_class': , @@ -1310,6 +1334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm 10 Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1366,6 +1391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 CH2O', 'options': dict({ }), 'original_device_class': , @@ -1419,6 +1445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 CO2', 'options': dict({ }), 'original_device_class': , @@ -1472,6 +1499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 PM25', 'options': dict({ }), 'original_device_class': , @@ -1525,6 +1553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 PPB', 'options': dict({ }), 'original_device_class': None, @@ -1577,6 +1606,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimmer switch 3 Battery', 'options': dict({ }), 'original_device_class': , @@ -1630,6 +1660,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IKEA Starkvind Filter time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1688,6 +1719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 CH2O', 'options': dict({ }), 'original_device_class': , @@ -1741,6 +1773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 CO2', 'options': dict({ }), 'original_device_class': , @@ -1794,6 +1827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 PM25', 'options': dict({ }), 'original_device_class': , @@ -1847,6 +1881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 PPB', 'options': dict({ }), 'original_device_class': None, @@ -1899,6 +1934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 CH2O', 'options': dict({ }), 'original_device_class': , @@ -1952,6 +1988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 CO2', 'options': dict({ }), 'original_device_class': , @@ -2005,6 +2042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 PM25', 'options': dict({ }), 'original_device_class': , @@ -2058,6 +2096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AirQuality 1 PPB', 'options': dict({ }), 'original_device_class': None, @@ -2110,6 +2149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FYRTUR block-out roller blind Battery', 'options': dict({ }), 'original_device_class': , @@ -2164,6 +2204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CarbonDioxide 35', 'options': dict({ }), 'original_device_class': , @@ -2217,6 +2258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption 15', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2273,6 +2315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daylight', 'options': dict({ }), 'original_device_class': None, @@ -2326,6 +2369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Formaldehyde 34', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/deconz/test_device_trigger.py b/tests/components/deconz/test_device_trigger.py index 5781a4c3ed5..8184056e39f 100644 --- a/tests/components/deconz/test_device_trigger.py +++ b/tests/components/deconz/test_device_trigger.py @@ -39,11 +39,6 @@ from .conftest import WebsocketDataType from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( "sensor_payload", [ diff --git a/tests/components/default_config/test_init.py b/tests/components/default_config/test_init.py index 1a6665b2404..9bff213bb74 100644 --- a/tests/components/default_config/test_init.py +++ b/tests/components/default_config/test_init.py @@ -10,11 +10,6 @@ from homeassistant.helpers import recorder as recorder_helper from homeassistant.setup import async_setup_component -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) def mock_ssdp(): """Mock ssdp.""" diff --git a/tests/components/demo/conftest.py b/tests/components/demo/conftest.py index 56aabac0280..e3b2bec001b 100644 --- a/tests/components/demo/conftest.py +++ b/tests/components/demo/conftest.py @@ -10,11 +10,6 @@ from homeassistant.setup import async_setup_component from tests.components.light.conftest import mock_light_profiles # noqa: F401 -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) async def setup_homeassistant(hass: HomeAssistant): """Set up the homeassistant integration.""" diff --git a/tests/components/device_automation/test_init.py b/tests/components/device_automation/test_init.py index c04dd242e61..a176199ff91 100644 --- a/tests/components/device_automation/test_init.py +++ b/tests/components/device_automation/test_init.py @@ -34,11 +34,6 @@ class MockDeviceEntry(dr.DeviceEntry): id: str = attr.ib(default="very_unique") -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture def fake_integration(hass: HomeAssistant) -> None: """Set up a mock integration with device automation support.""" diff --git a/tests/components/device_automation/test_toggle_entity.py b/tests/components/device_automation/test_toggle_entity.py index a7b2f8a3b75..8f42b9101f4 100644 --- a/tests/components/device_automation/test_toggle_entity.py +++ b/tests/components/device_automation/test_toggle_entity.py @@ -14,11 +14,6 @@ from homeassistant.util import dt as dt_util from tests.common import MockConfigEntry, async_fire_time_changed -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_if_fires_on_state_change( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/device_tracker/test_device_condition.py b/tests/components/device_tracker/test_device_condition.py index aff020d61a8..91983ca6ed8 100644 --- a/tests/components/device_tracker/test_device_condition.py +++ b/tests/components/device_tracker/test_device_condition.py @@ -15,11 +15,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/device_tracker/test_device_trigger.py b/tests/components/device_tracker/test_device_trigger.py index 860c470fc37..0466df96a9e 100644 --- a/tests/components/device_tracker/test_device_trigger.py +++ b/tests/components/device_tracker/test_device_trigger.py @@ -19,12 +19,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - AWAY_LATITUDE = 32.881011 AWAY_LONGITUDE = -117.234758 diff --git a/tests/components/device_tracker/test_trigger.py b/tests/components/device_tracker/test_trigger.py index 5abf0d437f9..19ac9c929c2 100644 --- a/tests/components/device_tracker/test_trigger.py +++ b/tests/components/device_tracker/test_trigger.py @@ -1,8 +1,6 @@ """Test device_tracker trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -15,7 +13,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -26,21 +24,6 @@ from tests.components import ( STATE_WORK_ZONE = "work" -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_device_trackers(hass: HomeAssistant) -> list[str]: """Create multiple device_trackers entities associated with different targets.""" @@ -64,7 +47,7 @@ async def test_device_tracker_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("device_tracker"), @@ -93,7 +76,7 @@ async def test_device_tracker_home_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the device_tracker home triggers when any device_tracker changes to a specific state.""" other_entity_ids = set(target_device_trackers) - {entity_id} @@ -122,7 +105,7 @@ async def test_device_tracker_home_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("device_tracker"), @@ -151,7 +134,7 @@ async def test_device_tracker_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the device_tracker home triggers when the first device_tracker changes to a specific state.""" other_entity_ids = set(target_device_trackers) - {entity_id} @@ -179,7 +162,7 @@ async def test_device_tracker_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("device_tracker"), @@ -208,7 +191,7 @@ async def test_device_tracker_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the device_tracker home triggers when the last device_tracker changes to a specific state.""" other_entity_ids = set(target_device_trackers) - {entity_id} diff --git a/tests/components/devolo_home_control/snapshots/test_binary_sensor.ambr b/tests/components/devolo_home_control/snapshots/test_binary_sensor.ambr index cb0c03e4b4e..dd110b65285 100644 --- a/tests/components/devolo_home_control/snapshots/test_binary_sensor.ambr +++ b/tests/components/devolo_home_control/snapshots/test_binary_sensor.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overload', 'options': dict({ }), 'original_device_class': , @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_control/snapshots/test_climate.ambr b/tests/components/devolo_home_control/snapshots/test_climate.ambr index a42eece1bf8..1a6dfe7ea4b 100644 --- a/tests/components/devolo_home_control/snapshots/test_climate.ambr +++ b/tests/components/devolo_home_control/snapshots/test_climate.ambr @@ -49,6 +49,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_control/snapshots/test_cover.ambr b/tests/components/devolo_home_control/snapshots/test_cover.ambr index 53a2582bd3d..c15e3b9fc87 100644 --- a/tests/components/devolo_home_control/snapshots/test_cover.ambr +++ b/tests/components/devolo_home_control/snapshots/test_cover.ambr @@ -36,6 +36,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/devolo_home_control/snapshots/test_light.ambr b/tests/components/devolo_home_control/snapshots/test_light.ambr index f66fd4add1f..ce7ca0a9e1e 100644 --- a/tests/components/devolo_home_control/snapshots/test_light.ambr +++ b/tests/components/devolo_home_control/snapshots/test_light.ambr @@ -43,6 +43,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -101,6 +102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_control/snapshots/test_sensor.ambr b/tests/components/devolo_home_control/snapshots/test_sensor.ambr index 77f18621364..f33da3cffc0 100644 --- a/tests/components/devolo_home_control/snapshots/test_sensor.ambr +++ b/tests/components/devolo_home_control/snapshots/test_sensor.ambr @@ -38,6 +38,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -90,6 +91,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brightness', 'options': dict({ }), 'original_device_class': None, @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -255,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/devolo_home_control/snapshots/test_siren.ambr b/tests/components/devolo_home_control/snapshots/test_siren.ambr index 463af865ad8..da0cbbda503 100644 --- a/tests/components/devolo_home_control/snapshots/test_siren.ambr +++ b/tests/components/devolo_home_control/snapshots/test_siren.ambr @@ -41,6 +41,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -153,6 +155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_control/snapshots/test_switch.ambr b/tests/components/devolo_home_control/snapshots/test_switch.ambr index 1047f0580c5..e5cf584521c 100644 --- a/tests/components/devolo_home_control/snapshots/test_switch.ambr +++ b/tests/components/devolo_home_control/snapshots/test_switch.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_network/snapshots/test_binary_sensor.ambr b/tests/components/devolo_home_network/snapshots/test_binary_sensor.ambr index 5099c9881e7..098ec123a03 100644 --- a/tests/components/devolo_home_network/snapshots/test_binary_sensor.ambr +++ b/tests/components/devolo_home_network/snapshots/test_binary_sensor.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connected to router', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/devolo_home_network/snapshots/test_button.ambr b/tests/components/devolo_home_network/snapshots/test_button.ambr index d7c1ae06a6b..28b178b5abb 100644 --- a/tests/components/devolo_home_network/snapshots/test_button.ambr +++ b/tests/components/devolo_home_network/snapshots/test_button.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify device with a blinking LED', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart device', 'options': dict({ }), 'original_device_class': , @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start PLC pairing', 'options': dict({ }), 'original_device_class': None, @@ -179,6 +182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start WPS', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_network/snapshots/test_image.ambr b/tests/components/devolo_home_network/snapshots/test_image.ambr index 5817b502eff..ebd120605c0 100644 --- a/tests/components/devolo_home_network/snapshots/test_image.ambr +++ b/tests/components/devolo_home_network/snapshots/test_image.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Guest Wi-Fi credentials as QR code', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_network/snapshots/test_sensor.ambr b/tests/components/devolo_home_network/snapshots/test_sensor.ambr index d22916552a5..243529aa00c 100644 --- a/tests/components/devolo_home_network/snapshots/test_sensor.ambr +++ b/tests/components/devolo_home_network/snapshots/test_sensor.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connected PLC devices', 'options': dict({ }), 'original_device_class': None, @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connected Wi-Fi clients', 'options': dict({ }), 'original_device_class': None, @@ -133,6 +135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart of the device', 'options': dict({ }), 'original_device_class': , @@ -181,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Neighboring Wi-Fi networks', 'options': dict({ }), 'original_device_class': None, @@ -231,6 +235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PLC downlink PHY rate (test2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -284,6 +289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PLC downlink PHY rate (test2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/devolo_home_network/snapshots/test_switch.ambr b/tests/components/devolo_home_network/snapshots/test_switch.ambr index 85b36b425b4..f5681c5e10a 100644 --- a/tests/components/devolo_home_network/snapshots/test_switch.ambr +++ b/tests/components/devolo_home_network/snapshots/test_switch.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Enable guest Wi-Fi', 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Enable LEDs', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/devolo_home_network/snapshots/test_update.ambr b/tests/components/devolo_home_network/snapshots/test_update.ambr index 92301447ac9..a1f32024d7c 100644 --- a/tests/components/devolo_home_network/snapshots/test_update.ambr +++ b/tests/components/devolo_home_network/snapshots/test_update.ambr @@ -46,6 +46,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/discovergy/snapshots/test_sensor.ambr b/tests/components/discovergy/snapshots/test_sensor.ambr index 84da04a7114..5024cd7dd22 100644 --- a/tests/components/discovergy/snapshots/test_sensor.ambr +++ b/tests/components/discovergy/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last transmitted', 'options': dict({ }), 'original_device_class': , @@ -60,6 +61,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 4, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last transmitted', 'options': dict({ }), 'original_device_class': , @@ -210,6 +214,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total gas consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 4, diff --git a/tests/components/drop_connect/snapshots/test_binary_sensor.ambr b/tests/components/drop_connect/snapshots/test_binary_sensor.ambr index 0db2fe508e9..47fc44beb7c 100644 --- a/tests/components/drop_connect/snapshots/test_binary_sensor.ambr +++ b/tests/components/drop_connect/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak detected', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification unread', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak detected', 'options': dict({ }), 'original_device_class': , @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak detected', 'options': dict({ }), 'original_device_class': , @@ -313,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak detected', 'options': dict({ }), 'original_device_class': , @@ -362,6 +369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump status', 'options': dict({ }), 'original_device_class': None, @@ -410,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak detected', 'options': dict({ }), 'original_device_class': , @@ -459,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve capacity in use', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/droplet/snapshots/test_sensor.ambr b/tests/components/droplet/snapshots/test_sensor.ambr index aa92d6df0af..6a9e0cb1e21 100644 --- a/tests/components/droplet/snapshots/test_sensor.ambr +++ b/tests/components/droplet/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Server status', 'options': dict({ }), 'original_device_class': , @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal quality', 'options': dict({ }), 'original_device_class': , @@ -201,6 +204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/ecovacs/snapshots/test_binary_sensor.ambr b/tests/components/ecovacs/snapshots/test_binary_sensor.ambr index 205ce783b8c..160c6b3c5ed 100644 --- a/tests/components/ecovacs/snapshots/test_binary_sensor.ambr +++ b/tests/components/ecovacs/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mop attached', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_button.ambr b/tests/components/ecovacs/snapshots/test_button.ambr index 21b7d6105f1..d18dc4fa499 100644 --- a/tests/components/ecovacs/snapshots/test_button.ambr +++ b/tests/components/ecovacs/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset blade lifespan', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset lens brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Empty dustbin', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relocate', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter lifespan', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset main brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset round mop lifespan', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset side brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset unit care lifespan', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relocate', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter lifespan', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset main brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset side brush lifespan', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_event.ambr b/tests/components/ecovacs/snapshots/test_event.ambr index 3f72a803c6d..c4510c8c3ca 100644 --- a/tests/components/ecovacs/snapshots/test_event.ambr +++ b/tests/components/ecovacs/snapshots/test_event.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last job', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_lawn_mower.ambr b/tests/components/ecovacs/snapshots/test_lawn_mower.ambr index 99f4ba25bd4..edd52cb3489 100644 --- a/tests/components/ecovacs/snapshots/test_lawn_mower.ambr +++ b/tests/components/ecovacs/snapshots/test_lawn_mower.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -55,6 +56,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_number.ambr b/tests/components/ecovacs/snapshots/test_number.ambr index f35ee92ceb8..650a6f5a717 100644 --- a/tests/components/ecovacs/snapshots/test_number.ambr +++ b/tests/components/ecovacs/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cut direction', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clean count', 'options': dict({ }), 'original_device_class': None, @@ -197,6 +200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -254,6 +258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water flow level', 'options': dict({ }), 'original_device_class': None, @@ -311,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_select.ambr b/tests/components/ecovacs/snapshots/test_select.ambr index b81a51ef0d3..b57fe4474e8 100644 --- a/tests/components/ecovacs/snapshots/test_select.ambr +++ b/tests/components/ecovacs/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active map', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-empty frequency', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Work mode', 'options': dict({ }), 'original_device_class': None, @@ -200,6 +203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active map', 'options': dict({ }), 'original_device_class': None, @@ -257,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-empty frequency', 'options': dict({ }), 'original_device_class': None, @@ -315,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water flow level', 'options': dict({ }), 'original_device_class': None, @@ -373,6 +379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active map', 'options': dict({ }), 'original_device_class': None, @@ -432,6 +439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water flow level', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_sensor.ambr b/tests/components/ecovacs/snapshots/test_sensor.ambr index a3a891e6a87..5bd7aecfb55 100644 --- a/tests/components/ecovacs/snapshots/test_sensor.ambr +++ b/tests/components/ecovacs/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifespan', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -169,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -226,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area cleaned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -282,6 +287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -332,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Blade lifespan', 'options': dict({ }), 'original_device_class': None, @@ -381,6 +388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -437,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': None, @@ -486,6 +495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IP address', 'options': dict({ }), 'original_device_class': None, @@ -534,6 +544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lens brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -585,6 +596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total area cleaned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -641,6 +653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -700,6 +713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleanings', 'options': dict({ }), 'original_device_class': None, @@ -749,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi RSSI', 'options': dict({ }), 'original_device_class': None, @@ -797,6 +812,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -845,6 +861,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area cleaned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -901,6 +918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -951,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1007,6 +1026,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': None, @@ -1056,6 +1076,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifespan', 'options': dict({ }), 'original_device_class': None, @@ -1105,6 +1126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IP address', 'options': dict({ }), 'original_device_class': None, @@ -1153,6 +1175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -1202,6 +1225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Round mop lifespan', 'options': dict({ }), 'original_device_class': None, @@ -1251,6 +1275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -1307,6 +1332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Station state', 'options': dict({ }), 'original_device_class': , @@ -1364,6 +1390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total area cleaned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1420,6 +1447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1479,6 +1507,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleanings', 'options': dict({ }), 'original_device_class': None, @@ -1528,6 +1557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Unit care lifespan', 'options': dict({ }), 'original_device_class': None, @@ -1577,6 +1607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi RSSI', 'options': dict({ }), 'original_device_class': None, @@ -1625,6 +1656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -1673,6 +1705,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Area cleaned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1729,6 +1762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1779,6 +1813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1835,6 +1870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': None, @@ -1884,6 +1920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifespan', 'options': dict({ }), 'original_device_class': None, @@ -1933,6 +1970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IP address', 'options': dict({ }), 'original_device_class': None, @@ -1981,6 +2019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -2030,6 +2069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush lifespan', 'options': dict({ }), 'original_device_class': None, @@ -2081,6 +2121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total area cleaned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2137,6 +2178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2196,6 +2238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleanings', 'options': dict({ }), 'original_device_class': None, @@ -2245,6 +2288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi RSSI', 'options': dict({ }), 'original_device_class': None, @@ -2293,6 +2337,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ecovacs/snapshots/test_switch.ambr b/tests/components/ecovacs/snapshots/test_switch.ambr index ae669b72fd0..3710712eaea 100644 --- a/tests/components/ecovacs/snapshots/test_switch.ambr +++ b/tests/components/ecovacs/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Advanced mode', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Border switch', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cross map border warning', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Move up warning', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safe protect', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'True detect', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Advanced mode', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carpet auto-boost suction', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Continuous cleaning', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Continuous cleaning', 'options': dict({ }), 'original_device_class': None, @@ -535,6 +546,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carpet auto-boost suction', 'options': dict({ }), 'original_device_class': None, @@ -570,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'True detect', 'options': dict({ }), 'original_device_class': None, @@ -605,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -640,6 +654,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Border spin', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/egauge/snapshots/test_sensor.ambr b/tests/components/egauge/snapshots/test_sensor.ambr index 22b4be6e916..fd4086e58d1 100644 --- a/tests/components/egauge/snapshots/test_sensor.ambr +++ b/tests/components/egauge/snapshots/test_sensor.ambr @@ -53,6 +53,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -112,6 +113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -168,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -227,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/eheimdigital/snapshots/test_climate.ambr b/tests/components/eheimdigital/snapshots/test_climate.ambr index 24b503f2ed7..376411690d1 100644 --- a/tests/components/eheimdigital/snapshots/test_climate.ambr +++ b/tests/components/eheimdigital/snapshots/test_climate.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -111,6 +112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/eheimdigital/snapshots/test_light.ambr b/tests/components/eheimdigital/snapshots/test_light.ambr index f9dedeb5cfc..f9ebff733ff 100644 --- a/tests/components/eheimdigital/snapshots/test_light.ambr +++ b/tests/components/eheimdigital/snapshots/test_light.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Channel 1', 'options': dict({ }), 'original_device_class': None, @@ -92,6 +93,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Channel 0', 'options': dict({ }), 'original_device_class': None, @@ -157,6 +159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Channel 1', 'options': dict({ }), 'original_device_class': None, @@ -222,6 +225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Channel 0', 'options': dict({ }), 'original_device_class': None, @@ -287,6 +291,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Channel 1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/eheimdigital/snapshots/test_number.ambr b/tests/components/eheimdigital/snapshots/test_number.ambr index 1c354d12169..a8e3767cf6a 100644 --- a/tests/components/eheimdigital/snapshots/test_number.ambr +++ b/tests/components/eheimdigital/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System LED brightness', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Day speed', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual speed', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night speed', 'options': dict({ }), 'original_device_class': None, @@ -257,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System LED brightness', 'options': dict({ }), 'original_device_class': None, @@ -315,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High pulse duration', 'options': dict({ }), 'original_device_class': , @@ -374,6 +380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low pulse duration', 'options': dict({ }), 'original_device_class': , @@ -433,6 +440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System LED brightness', 'options': dict({ }), 'original_device_class': None, @@ -491,6 +499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night temperature offset', 'options': dict({ }), 'original_device_class': , @@ -549,6 +558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System LED brightness', 'options': dict({ }), 'original_device_class': None, @@ -607,6 +617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/eheimdigital/snapshots/test_select.ambr b/tests/components/eheimdigital/snapshots/test_select.ambr index c23041c5a26..1a88c88a0f0 100644 --- a/tests/components/eheimdigital/snapshots/test_select.ambr +++ b/tests/components/eheimdigital/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter mode', 'options': dict({ }), 'original_device_class': None, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Constant flow speed', 'options': dict({ }), 'original_device_class': None, @@ -181,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Day speed', 'options': dict({ }), 'original_device_class': None, @@ -254,6 +257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter mode', 'options': dict({ }), 'original_device_class': None, @@ -326,6 +330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High pulse speed', 'options': dict({ }), 'original_device_class': None, @@ -410,6 +415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low pulse speed', 'options': dict({ }), 'original_device_class': None, @@ -494,6 +500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual speed', 'options': dict({ }), 'original_device_class': None, @@ -578,6 +585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night speed', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/eheimdigital/snapshots/test_sensor.ambr b/tests/components/eheimdigital/snapshots/test_sensor.ambr index 25ec5c10a51..33dcdb517bf 100644 --- a/tests/components/eheimdigital/snapshots/test_sensor.ambr +++ b/tests/components/eheimdigital/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current speed', 'options': dict({ }), 'original_device_class': None, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error code', 'options': dict({ }), 'original_device_class': , @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining hours until service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -185,6 +188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -238,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining hours until service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/eheimdigital/snapshots/test_switch.ambr b/tests/components/eheimdigital/snapshots/test_switch.ambr index 6c126adeb01..3fae9269feb 100644 --- a/tests/components/eheimdigital/snapshots/test_switch.ambr +++ b/tests/components/eheimdigital/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/eheimdigital/snapshots/test_time.ambr b/tests/components/eheimdigital/snapshots/test_time.ambr index df5c9cd589e..b5eeacaca5d 100644 --- a/tests/components/eheimdigital/snapshots/test_time.ambr +++ b/tests/components/eheimdigital/snapshots/test_time.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Day start time', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night start time', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Day start time', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night start time', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Day start time', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night start time', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/elgato/snapshots/test_button.ambr b/tests/components/elgato/snapshots/test_button.ambr index 85f9fadd2a0..c8c41d530ac 100644 --- a/tests/components/elgato/snapshots/test_button.ambr +++ b/tests/components/elgato/snapshots/test_button.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -118,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/elgato/snapshots/test_light.ambr b/tests/components/elgato/snapshots/test_light.ambr index 5dbc21f62df..c266274f4bf 100644 --- a/tests/components/elgato/snapshots/test_light.ambr +++ b/tests/components/elgato/snapshots/test_light.ambr @@ -66,6 +66,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -184,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -302,6 +304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/elgato/snapshots/test_sensor.ambr b/tests/components/elgato/snapshots/test_sensor.ambr index f53f8d223bd..7e216c24deb 100644 --- a/tests/components/elgato/snapshots/test_sensor.ambr +++ b/tests/components/elgato/snapshots/test_sensor.ambr @@ -38,6 +38,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -129,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -223,6 +225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -317,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -408,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/elgato/snapshots/test_switch.ambr b/tests/components/elgato/snapshots/test_switch.ambr index 61235f17ece..e6fcd2f1427 100644 --- a/tests/components/elgato/snapshots/test_switch.ambr +++ b/tests/components/elgato/snapshots/test_switch.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saving', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +117,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Studio mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/elmax/snapshots/test_alarm_control_panel.ambr b/tests/components/elmax/snapshots/test_alarm_control_panel.ambr index 77d41d50710..40846b89575 100644 --- a/tests/components/elmax/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/elmax/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AREA 1', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AREA 2', 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AREA 3', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/elmax/snapshots/test_binary_sensor.ambr b/tests/components/elmax/snapshots/test_binary_sensor.ambr index 5fb9b9fd06e..f3ab165ab85 100644 --- a/tests/components/elmax/snapshots/test_binary_sensor.ambr +++ b/tests/components/elmax/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 01', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 02e', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 03a', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 04', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 05', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 06', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 07', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ZONA 08', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/elmax/snapshots/test_cover.ambr b/tests/components/elmax/snapshots/test_cover.ambr index 5d30dc6a570..239cc2359f4 100644 --- a/tests/components/elmax/snapshots/test_cover.ambr +++ b/tests/components/elmax/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ESPAN.DOM.01', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/elmax/snapshots/test_switch.ambr b/tests/components/elmax/snapshots/test_switch.ambr index d278c3e9854..567be6f93a8 100644 --- a/tests/components/elmax/snapshots/test_switch.ambr +++ b/tests/components/elmax/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'USCITA 02', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/emoncms/snapshots/test_sensor.ambr b/tests/components/emoncms/snapshots/test_sensor.ambr index 1ad7a6c3aa5..6b2a2de38b9 100644 --- a/tests/components/emoncms/snapshots/test_sensor.ambr +++ b/tests/components/emoncms/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature tag parameter 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/emulated_hue/conftest.py b/tests/components/emulated_hue/conftest.py deleted file mode 100644 index e25a2099227..00000000000 --- a/tests/components/emulated_hue/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Conftest for emulated_hue tests.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/energenie_power_sockets/snapshots/test_switch.ambr b/tests/components/energenie_power_sockets/snapshots/test_switch.ambr index 56e6bc52361..b65fb5b9a48 100644 --- a/tests/components/energenie_power_sockets/snapshots/test_switch.ambr +++ b/tests/components/energenie_power_sockets/snapshots/test_switch.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 0', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -181,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 3', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/energyzero/snapshots/test_sensor.ambr b/tests/components/energyzero/snapshots/test_sensor.ambr index c0041bc0e50..db34d35ff47 100644 --- a/tests/components/energyzero/snapshots/test_sensor.ambr +++ b/tests/components/energyzero/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -173,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -223,6 +227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -273,6 +278,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -323,6 +329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -373,6 +380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -423,6 +431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -475,6 +484,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -526,6 +536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/enphase_envoy/snapshots/test_binary_sensor.ambr b/tests/components/enphase_envoy/snapshots/test_binary_sensor.ambr index 18e7a9c9008..f81d3fe0e4c 100644 --- a/tests/components/enphase_envoy/snapshots/test_binary_sensor.ambr +++ b/tests/components/enphase_envoy/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC switch', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': , @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC switch', 'options': dict({ }), 'original_device_class': None, @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': , @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid status', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/enphase_envoy/snapshots/test_diagnostics.ambr b/tests/components/enphase_envoy/snapshots/test_diagnostics.ambr index 799c435058c..6d1e167db51 100644 --- a/tests/components/enphase_envoy/snapshots/test_diagnostics.ambr +++ b/tests/components/enphase_envoy/snapshots/test_diagnostics.ambr @@ -85,6 +85,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -138,6 +139,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -189,6 +191,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -241,6 +244,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -331,6 +335,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -381,6 +386,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -419,6 +425,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ }), 'original_device_class': 'current', @@ -457,6 +464,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -495,6 +503,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ }), 'original_device_class': 'current', @@ -533,6 +542,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ }), 'original_device_class': 'frequency', @@ -571,6 +581,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': 'temperature', @@ -609,6 +620,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -650,6 +662,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ }), 'original_device_class': 'energy', @@ -688,6 +701,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ }), 'original_device_class': 'duration', @@ -726,6 +740,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ }), 'original_device_class': 'energy', @@ -764,6 +779,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ }), 'original_device_class': 'power', @@ -800,6 +816,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -966,6 +983,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1019,6 +1037,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1070,6 +1089,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1122,6 +1142,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1212,6 +1233,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1262,6 +1284,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -1300,6 +1323,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ }), 'original_device_class': 'current', @@ -1338,6 +1362,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -1376,6 +1401,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ }), 'original_device_class': 'current', @@ -1414,6 +1440,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ }), 'original_device_class': 'frequency', @@ -1452,6 +1479,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': 'temperature', @@ -1490,6 +1518,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -1531,6 +1560,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ }), 'original_device_class': 'energy', @@ -1569,6 +1599,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ }), 'original_device_class': 'duration', @@ -1607,6 +1638,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ }), 'original_device_class': 'energy', @@ -1645,6 +1677,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ }), 'original_device_class': 'power', @@ -1681,6 +1714,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -1891,6 +1925,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1944,6 +1979,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1995,6 +2031,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2047,6 +2084,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2137,6 +2175,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2187,6 +2226,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -2225,6 +2265,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ }), 'original_device_class': 'current', @@ -2263,6 +2304,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -2301,6 +2343,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ }), 'original_device_class': 'current', @@ -2339,6 +2382,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ }), 'original_device_class': 'frequency', @@ -2377,6 +2421,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': 'temperature', @@ -2415,6 +2460,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -2456,6 +2502,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ }), 'original_device_class': 'energy', @@ -2494,6 +2541,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ }), 'original_device_class': 'duration', @@ -2532,6 +2580,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ }), 'original_device_class': 'energy', @@ -2570,6 +2619,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ }), 'original_device_class': 'power', @@ -2606,6 +2656,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -2837,6 +2888,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2887,6 +2939,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -2925,6 +2978,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ }), 'original_device_class': 'current', @@ -2963,6 +3017,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -3001,6 +3056,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ }), 'original_device_class': 'current', @@ -3039,6 +3095,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ }), 'original_device_class': 'frequency', @@ -3077,6 +3134,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': 'temperature', @@ -3115,6 +3173,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -3156,6 +3215,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ }), 'original_device_class': 'energy', @@ -3194,6 +3254,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ }), 'original_device_class': 'duration', @@ -3232,6 +3293,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ }), 'original_device_class': 'energy', @@ -3270,6 +3332,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ }), 'original_device_class': 'power', @@ -3306,6 +3369,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -3385,6 +3449,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3438,6 +3503,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3489,6 +3555,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3541,6 +3608,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3727,6 +3795,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3780,6 +3849,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3831,6 +3901,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3883,6 +3954,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3936,6 +4008,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3989,6 +4062,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4040,6 +4114,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4092,6 +4167,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4145,6 +4221,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -4186,6 +4263,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4227,6 +4305,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -4268,6 +4347,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4307,6 +4387,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4348,6 +4429,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -4389,6 +4471,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -4430,6 +4513,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4469,6 +4553,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4510,6 +4595,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -4551,6 +4637,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power production l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -4592,6 +4679,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4631,6 +4719,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production last seven days l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4672,6 +4761,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -4713,6 +4803,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power consumption l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -4754,6 +4845,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption today l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4793,6 +4885,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption last seven days l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4834,6 +4927,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy consumption l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -4875,6 +4969,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power consumption l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -4916,6 +5011,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption today l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4955,6 +5051,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption last seven days l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -4996,6 +5093,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy consumption l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -5037,6 +5135,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current power consumption l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -5078,6 +5177,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption today l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -5117,6 +5217,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy consumption last seven days l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -5158,6 +5259,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy consumption l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -5199,6 +5301,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Balanced net power consumption l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -5240,6 +5343,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -5281,6 +5385,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Balanced net power consumption l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -5322,6 +5427,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -5363,6 +5469,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Balanced net power consumption l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -5404,6 +5511,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -5445,6 +5553,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5498,6 +5607,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5551,6 +5661,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5604,6 +5715,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5657,6 +5769,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5710,6 +5823,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current battery discharge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5763,6 +5877,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency net consumption CT', 'options': dict({ }), 'original_device_class': 'frequency', @@ -5801,6 +5916,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ }), 'original_device_class': 'frequency', @@ -5839,6 +5955,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency storage CT', 'options': dict({ }), 'original_device_class': 'frequency', @@ -5877,6 +5994,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage net consumption CT', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -5918,6 +6036,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -5959,6 +6078,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage storage CT', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -6000,6 +6120,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Net consumption CT current', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -6041,6 +6162,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -6082,6 +6204,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Storage CT current', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -6123,6 +6246,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor net consumption CT', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -6161,6 +6285,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -6199,6 +6324,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor storage CT', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -6241,6 +6367,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status net consumption CT', 'options': dict({ }), 'original_device_class': 'enum', @@ -6283,6 +6410,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': 'enum', @@ -6325,6 +6453,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status storage CT', 'options': dict({ }), 'original_device_class': 'enum', @@ -6361,6 +6490,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT', 'options': dict({ }), 'original_device_class': None, @@ -6397,6 +6527,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -6433,6 +6564,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active storage CT', 'options': dict({ }), 'original_device_class': None, @@ -6471,6 +6603,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -6512,6 +6645,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -6553,6 +6687,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy production l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -6594,6 +6729,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy charged l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -6635,6 +6771,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current net power consumption l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -6676,6 +6813,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current battery discharge l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -6717,6 +6855,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency net consumption CT l1', 'options': dict({ }), 'original_device_class': 'frequency', @@ -6755,6 +6894,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency production CT l1', 'options': dict({ }), 'original_device_class': 'frequency', @@ -6793,6 +6933,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency storage CT l1', 'options': dict({ }), 'original_device_class': 'frequency', @@ -6831,6 +6972,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage net consumption CT l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -6872,6 +7014,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage production CT l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -6913,6 +7056,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage storage CT l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -6954,6 +7098,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Net consumption CT current l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -6995,6 +7140,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Production CT current l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -7036,6 +7182,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Storage CT current l1', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -7077,6 +7224,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor net consumption CT l1', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -7115,6 +7263,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor production CT l1', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -7153,6 +7302,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor storage CT l1', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -7195,6 +7345,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status net consumption CT l1', 'options': dict({ }), 'original_device_class': 'enum', @@ -7237,6 +7388,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status production CT l1', 'options': dict({ }), 'original_device_class': 'enum', @@ -7279,6 +7431,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status storage CT l1', 'options': dict({ }), 'original_device_class': 'enum', @@ -7315,6 +7468,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l1', 'options': dict({ }), 'original_device_class': None, @@ -7351,6 +7505,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active production CT l1', 'options': dict({ }), 'original_device_class': None, @@ -7387,6 +7542,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active storage CT l1', 'options': dict({ }), 'original_device_class': None, @@ -7425,6 +7581,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -7466,6 +7623,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -7507,6 +7665,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy production l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -7548,6 +7707,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy charged l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -7589,6 +7749,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current net power consumption l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -7630,6 +7791,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current battery discharge l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -7671,6 +7833,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency net consumption CT l2', 'options': dict({ }), 'original_device_class': 'frequency', @@ -7709,6 +7872,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency production CT l2', 'options': dict({ }), 'original_device_class': 'frequency', @@ -7747,6 +7911,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency storage CT l2', 'options': dict({ }), 'original_device_class': 'frequency', @@ -7785,6 +7950,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage net consumption CT l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -7826,6 +7992,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage production CT l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -7867,6 +8034,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage storage CT l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -7908,6 +8076,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Net consumption CT current l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -7949,6 +8118,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Production CT current l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -7990,6 +8160,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Storage CT current l2', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -8031,6 +8202,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor net consumption CT l2', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -8069,6 +8241,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor production CT l2', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -8107,6 +8280,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor storage CT l2', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -8149,6 +8323,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status net consumption CT l2', 'options': dict({ }), 'original_device_class': 'enum', @@ -8191,6 +8366,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status production CT l2', 'options': dict({ }), 'original_device_class': 'enum', @@ -8233,6 +8409,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status storage CT l2', 'options': dict({ }), 'original_device_class': 'enum', @@ -8269,6 +8446,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l2', 'options': dict({ }), 'original_device_class': None, @@ -8305,6 +8483,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active production CT l2', 'options': dict({ }), 'original_device_class': None, @@ -8341,6 +8520,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active storage CT l2', 'options': dict({ }), 'original_device_class': None, @@ -8379,6 +8559,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -8420,6 +8601,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -8461,6 +8643,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime net energy production l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -8502,6 +8685,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime battery energy charged l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'MWh', @@ -8543,6 +8727,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current net power consumption l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -8584,6 +8769,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Current battery discharge l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kW', @@ -8625,6 +8811,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency net consumption CT l3', 'options': dict({ }), 'original_device_class': 'frequency', @@ -8663,6 +8850,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency production CT l3', 'options': dict({ }), 'original_device_class': 'frequency', @@ -8701,6 +8889,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency storage CT l3', 'options': dict({ }), 'original_device_class': 'frequency', @@ -8739,6 +8928,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage net consumption CT l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -8780,6 +8970,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage production CT l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -8821,6 +9012,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Voltage storage CT l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'V', @@ -8862,6 +9054,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Net consumption CT current l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -8903,6 +9096,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Production CT current l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -8944,6 +9138,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Storage CT current l3', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'A', @@ -8985,6 +9180,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor net consumption CT l3', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -9023,6 +9219,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor production CT l3', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -9061,6 +9258,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power factor storage CT l3', 'options': dict({ }), 'original_device_class': 'power_factor', @@ -9103,6 +9301,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status net consumption CT l3', 'options': dict({ }), 'original_device_class': 'enum', @@ -9145,6 +9344,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status production CT l3', 'options': dict({ }), 'original_device_class': 'enum', @@ -9187,6 +9387,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Metering status storage CT l3', 'options': dict({ }), 'original_device_class': 'enum', @@ -9223,6 +9424,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l3', 'options': dict({ }), 'original_device_class': None, @@ -9259,6 +9461,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active production CT l3', 'options': dict({ }), 'original_device_class': None, @@ -9295,6 +9498,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Meter status flags active storage CT l3', 'options': dict({ }), 'original_device_class': None, @@ -9333,6 +9537,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': 'battery', @@ -9380,6 +9585,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -9427,6 +9633,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Available battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9477,6 +9684,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Reserve battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9525,6 +9733,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9609,6 +9818,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': 'connectivity', @@ -9652,6 +9862,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC switch', 'options': dict({ }), 'original_device_class': None, @@ -9696,6 +9907,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9744,6 +9956,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -9789,6 +10002,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': 'battery', @@ -9836,6 +10050,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9886,6 +10101,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9971,6 +10187,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': 'connectivity', @@ -10014,6 +10231,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Grid status', 'options': dict({ }), 'original_device_class': None, @@ -10061,6 +10279,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -10115,6 +10334,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Storage mode', 'options': dict({ }), 'original_device_class': None, @@ -10164,6 +10384,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10212,6 +10433,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -10255,6 +10477,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Grid enabled', 'options': dict({ }), 'original_device_class': None, @@ -10297,6 +10520,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Charge from grid', 'options': dict({ }), 'original_device_class': None, @@ -10376,6 +10600,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': 'connectivity', @@ -10421,6 +10646,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10469,6 +10695,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -10512,6 +10739,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Grid status', 'options': dict({ }), 'original_device_class': None, @@ -10554,6 +10782,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Admin state', 'options': dict({ }), 'original_device_class': None, @@ -10596,6 +10825,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MID state', 'options': dict({ }), 'original_device_class': None, @@ -10675,6 +10905,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Communicating', 'options': dict({ }), 'original_device_class': 'connectivity', @@ -10718,6 +10949,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', @@ -10803,6 +11035,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Cutoff battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -10855,6 +11088,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Restore battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -10907,6 +11141,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -10960,6 +11195,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Grid action', 'options': dict({ }), 'original_device_class': None, @@ -11015,6 +11251,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Microgrid action', 'options': dict({ }), 'original_device_class': None, @@ -11070,6 +11307,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Generator action', 'options': dict({ }), 'original_device_class': None, @@ -11118,6 +11356,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -11202,6 +11441,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Cutoff battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -11254,6 +11494,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Restore battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -11306,6 +11547,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -11359,6 +11601,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Grid action', 'options': dict({ }), 'original_device_class': None, @@ -11414,6 +11657,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Microgrid action', 'options': dict({ }), 'original_device_class': None, @@ -11469,6 +11713,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Generator action', 'options': dict({ }), 'original_device_class': None, @@ -11517,6 +11762,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -11601,6 +11847,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Cutoff battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -11653,6 +11900,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Restore battery level', 'options': dict({ }), 'original_device_class': 'battery', @@ -11705,6 +11953,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -11758,6 +12007,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Grid action', 'options': dict({ }), 'original_device_class': None, @@ -11813,6 +12063,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Microgrid action', 'options': dict({ }), 'original_device_class': None, @@ -11868,6 +12119,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Generator action', 'options': dict({ }), 'original_device_class': None, @@ -11916,6 +12168,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -11997,6 +12250,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12047,6 +12301,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -12085,6 +12340,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ }), 'original_device_class': 'current', @@ -12123,6 +12379,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ }), 'original_device_class': 'voltage', @@ -12161,6 +12418,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ }), 'original_device_class': 'current', @@ -12199,6 +12457,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ }), 'original_device_class': 'frequency', @@ -12237,6 +12496,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': 'temperature', @@ -12275,6 +12535,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'kWh', @@ -12316,6 +12577,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ }), 'original_device_class': 'energy', @@ -12354,6 +12616,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ }), 'original_device_class': 'duration', @@ -12392,6 +12655,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ }), 'original_device_class': 'energy', @@ -12430,6 +12694,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ }), 'original_device_class': 'power', @@ -12466,6 +12731,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': 'timestamp', diff --git a/tests/components/enphase_envoy/snapshots/test_number.ambr b/tests/components/enphase_envoy/snapshots/test_number.ambr index 461d4028fbe..3941b8dd8fc 100644 --- a/tests/components/enphase_envoy/snapshots/test_number.ambr +++ b/tests/components/enphase_envoy/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': , @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cutoff battery level', 'options': dict({ }), 'original_device_class': , @@ -201,6 +204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restore battery level', 'options': dict({ }), 'original_device_class': , @@ -259,6 +263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cutoff battery level', 'options': dict({ }), 'original_device_class': , @@ -317,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restore battery level', 'options': dict({ }), 'original_device_class': , @@ -375,6 +381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cutoff battery level', 'options': dict({ }), 'original_device_class': , @@ -433,6 +440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restore battery level', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/enphase_envoy/snapshots/test_select.ambr b/tests/components/enphase_envoy/snapshots/test_select.ambr index 006b2c1a3fe..6c2df8e38cb 100644 --- a/tests/components/enphase_envoy/snapshots/test_select.ambr +++ b/tests/components/enphase_envoy/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage mode', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage mode', 'options': dict({ }), 'original_device_class': None, @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator action', 'options': dict({ }), 'original_device_class': None, @@ -206,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid action', 'options': dict({ }), 'original_device_class': None, @@ -267,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Microgrid action', 'options': dict({ }), 'original_device_class': None, @@ -326,6 +331,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -385,6 +391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator action', 'options': dict({ }), 'original_device_class': None, @@ -446,6 +453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid action', 'options': dict({ }), 'original_device_class': None, @@ -507,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Microgrid action', 'options': dict({ }), 'original_device_class': None, @@ -566,6 +575,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -625,6 +635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator action', 'options': dict({ }), 'original_device_class': None, @@ -686,6 +697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid action', 'options': dict({ }), 'original_device_class': None, @@ -747,6 +759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Microgrid action', 'options': dict({ }), 'original_device_class': None, @@ -806,6 +819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/enphase_envoy/snapshots/test_sensor.ambr b/tests/components/enphase_envoy/snapshots/test_sensor.ambr index 189a9dd62d5..1651c71c43f 100644 --- a/tests/components/enphase_envoy/snapshots/test_sensor.ambr +++ b/tests/components/enphase_envoy/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -79,6 +80,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -137,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -255,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -311,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -367,6 +373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -423,6 +430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -479,6 +487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -535,6 +544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -591,6 +601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -647,6 +658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -703,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -757,6 +770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -808,6 +822,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -867,6 +882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -923,6 +939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -979,6 +996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1038,6 +1056,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1097,6 +1116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1156,6 +1176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1213,6 +1234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1271,6 +1293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1328,6 +1351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1386,6 +1410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1445,6 +1470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1501,6 +1527,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1557,6 +1584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1616,6 +1644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1675,6 +1704,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1734,6 +1764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1793,6 +1824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1850,6 +1882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT', 'options': dict({ }), 'original_device_class': None, @@ -1898,6 +1931,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -1952,6 +1986,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT', 'options': dict({ }), 'original_device_class': , @@ -2012,6 +2047,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': , @@ -2068,6 +2104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2127,6 +2164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2182,6 +2220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2237,6 +2276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2296,6 +2336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2355,6 +2396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2414,6 +2456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2470,6 +2513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2526,6 +2570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2582,6 +2627,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2638,6 +2684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2694,6 +2741,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2750,6 +2798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2806,6 +2855,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2862,6 +2912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2916,6 +2967,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -2967,6 +3019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3026,6 +3079,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3082,6 +3136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3138,6 +3193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3196,6 +3252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': , @@ -3253,6 +3310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3309,6 +3367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3365,6 +3424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3416,6 +3476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -3467,6 +3528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3523,6 +3585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3579,6 +3642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aggregated available battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3633,6 +3697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aggregated Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3688,6 +3753,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aggregated battery SOC', 'options': dict({ }), 'original_device_class': , @@ -3741,6 +3807,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Available ACB battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3797,6 +3864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Available battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3853,6 +3921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -3912,6 +3981,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3963,6 +4033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4018,6 +4089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4077,6 +4149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4136,6 +4209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4195,6 +4269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4254,6 +4329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4313,6 +4389,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4370,6 +4447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4428,6 +4506,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4485,6 +4564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4543,6 +4623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4602,6 +4683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4658,6 +4740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4714,6 +4797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4770,6 +4854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4826,6 +4911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4882,6 +4968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4938,6 +5025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4994,6 +5082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5050,6 +5139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5109,6 +5199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5168,6 +5259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5227,6 +5319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5286,6 +5379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5345,6 +5439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5404,6 +5499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5463,6 +5559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5522,6 +5619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5581,6 +5679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5640,6 +5739,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -5697,6 +5797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT', 'options': dict({ }), 'original_device_class': None, @@ -5745,6 +5846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l1', 'options': dict({ }), 'original_device_class': None, @@ -5793,6 +5895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l2', 'options': dict({ }), 'original_device_class': None, @@ -5841,6 +5944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l3', 'options': dict({ }), 'original_device_class': None, @@ -5889,6 +5993,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -5937,6 +6042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l1', 'options': dict({ }), 'original_device_class': None, @@ -5985,6 +6091,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l2', 'options': dict({ }), 'original_device_class': None, @@ -6033,6 +6140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l3', 'options': dict({ }), 'original_device_class': None, @@ -6087,6 +6195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT', 'options': dict({ }), 'original_device_class': , @@ -6147,6 +6256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l1', 'options': dict({ }), 'original_device_class': , @@ -6207,6 +6317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l2', 'options': dict({ }), 'original_device_class': , @@ -6267,6 +6378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l3', 'options': dict({ }), 'original_device_class': , @@ -6327,6 +6439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': , @@ -6387,6 +6500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l1', 'options': dict({ }), 'original_device_class': , @@ -6447,6 +6561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l2', 'options': dict({ }), 'original_device_class': , @@ -6507,6 +6622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l3', 'options': dict({ }), 'original_device_class': , @@ -6563,6 +6679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -6622,6 +6739,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -6681,6 +6799,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -6740,6 +6859,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -6799,6 +6919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6854,6 +6975,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6909,6 +7031,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6964,6 +7087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7019,6 +7143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7074,6 +7199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7129,6 +7255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7184,6 +7311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7239,6 +7367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -7298,6 +7427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -7357,6 +7487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -7416,6 +7547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -7475,6 +7607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7531,6 +7664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': , @@ -7584,6 +7718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7643,6 +7778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7702,6 +7838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7761,6 +7898,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7820,6 +7958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7879,6 +8018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7938,6 +8078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7997,6 +8138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8056,6 +8198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8112,6 +8255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8168,6 +8312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8224,6 +8369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8280,6 +8426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8336,6 +8483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8392,6 +8540,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8448,6 +8597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8504,6 +8654,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8558,6 +8709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -8609,6 +8761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8668,6 +8821,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8724,6 +8878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -8780,6 +8935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8836,6 +8992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -8887,6 +9044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -8938,6 +9096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8994,6 +9153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9050,6 +9210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Available battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9106,6 +9267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9165,6 +9327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -9216,6 +9379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9271,6 +9435,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9330,6 +9495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9389,6 +9555,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9448,6 +9615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9507,6 +9675,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9566,6 +9735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9623,6 +9793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9681,6 +9852,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9738,6 +9910,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9796,6 +9969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9855,6 +10029,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9911,6 +10086,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9967,6 +10143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10023,6 +10200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10079,6 +10257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10135,6 +10314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10191,6 +10371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10247,6 +10428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10303,6 +10485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10362,6 +10545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10421,6 +10605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10480,6 +10665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10539,6 +10725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10598,6 +10785,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10657,6 +10845,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10716,6 +10905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10775,6 +10965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10834,6 +11025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10893,6 +11085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10950,6 +11143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT', 'options': dict({ }), 'original_device_class': None, @@ -10998,6 +11192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l1', 'options': dict({ }), 'original_device_class': None, @@ -11046,6 +11241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l2', 'options': dict({ }), 'original_device_class': None, @@ -11094,6 +11290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l3', 'options': dict({ }), 'original_device_class': None, @@ -11142,6 +11339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -11190,6 +11388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l1', 'options': dict({ }), 'original_device_class': None, @@ -11238,6 +11437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l2', 'options': dict({ }), 'original_device_class': None, @@ -11286,6 +11486,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l3', 'options': dict({ }), 'original_device_class': None, @@ -11340,6 +11541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT', 'options': dict({ }), 'original_device_class': , @@ -11400,6 +11602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l1', 'options': dict({ }), 'original_device_class': , @@ -11460,6 +11663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l2', 'options': dict({ }), 'original_device_class': , @@ -11520,6 +11724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l3', 'options': dict({ }), 'original_device_class': , @@ -11580,6 +11785,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': , @@ -11640,6 +11846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l1', 'options': dict({ }), 'original_device_class': , @@ -11700,6 +11907,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l2', 'options': dict({ }), 'original_device_class': , @@ -11760,6 +11968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l3', 'options': dict({ }), 'original_device_class': , @@ -11816,6 +12025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -11875,6 +12085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -11934,6 +12145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -11993,6 +12205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -12052,6 +12265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12107,6 +12321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12162,6 +12377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12217,6 +12433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12272,6 +12489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12327,6 +12545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12382,6 +12601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12437,6 +12657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12492,6 +12713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -12551,6 +12773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -12610,6 +12833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -12669,6 +12893,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -12728,6 +12953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12784,6 +13010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': , @@ -12837,6 +13064,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -12896,6 +13124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -12955,6 +13184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13014,6 +13244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13073,6 +13304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13132,6 +13364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13191,6 +13424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13250,6 +13484,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13309,6 +13544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13365,6 +13601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -13421,6 +13658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -13477,6 +13715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -13533,6 +13772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -13589,6 +13829,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -13645,6 +13886,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13701,6 +13943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -13757,6 +14000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13811,6 +14055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -13862,6 +14107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13921,6 +14167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13977,6 +14224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -14031,6 +14279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -14080,6 +14329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Admin state', 'options': dict({ }), 'original_device_class': None, @@ -14128,6 +14378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid status', 'options': dict({ }), 'original_device_class': None, @@ -14176,6 +14427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -14225,6 +14477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'MID state', 'options': dict({ }), 'original_device_class': None, @@ -14275,6 +14528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -14331,6 +14585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14387,6 +14642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -14438,6 +14694,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -14489,6 +14746,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14545,6 +14803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -14599,6 +14858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -14650,6 +14910,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -14706,6 +14967,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Available battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14762,6 +15024,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -14821,6 +15084,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -14880,6 +15144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -14939,6 +15204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -14998,6 +15264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -15049,6 +15316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15104,6 +15372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current battery discharge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15163,6 +15432,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current battery discharge l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15222,6 +15492,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current battery discharge l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15281,6 +15552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current battery discharge l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15340,6 +15612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15399,6 +15672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15458,6 +15732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15517,6 +15792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15576,6 +15852,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15635,6 +15912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15694,6 +15972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15753,6 +16032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15812,6 +16092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15871,6 +16152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15930,6 +16212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -15989,6 +16272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -16046,6 +16330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16102,6 +16387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16158,6 +16444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16214,6 +16501,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16272,6 +16560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16331,6 +16620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16390,6 +16680,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16449,6 +16740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16506,6 +16798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16562,6 +16855,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16618,6 +16912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16674,6 +16969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16732,6 +17028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16791,6 +17088,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16850,6 +17148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16909,6 +17208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16968,6 +17268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17024,6 +17325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17080,6 +17382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17136,6 +17439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17192,6 +17496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17248,6 +17553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17304,6 +17610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17360,6 +17667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17416,6 +17724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency storage CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17472,6 +17781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency storage CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17528,6 +17838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency storage CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17584,6 +17895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency storage CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17640,6 +17952,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -17699,6 +18012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -17758,6 +18072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -17817,6 +18132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -17876,6 +18192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -17935,6 +18252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy charged l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -17994,6 +18312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy charged l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18053,6 +18372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy charged l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18112,6 +18432,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18171,6 +18492,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18230,6 +18552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18289,6 +18612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery energy discharged l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18348,6 +18672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18407,6 +18732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18466,6 +18792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18525,6 +18852,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18584,6 +18912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18643,6 +18972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18702,6 +19032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18761,6 +19092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18820,6 +19152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18879,6 +19212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18938,6 +19272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -18997,6 +19332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -19056,6 +19392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -19115,6 +19452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -19174,6 +19512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -19233,6 +19572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -19290,6 +19630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT', 'options': dict({ }), 'original_device_class': None, @@ -19338,6 +19679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l1', 'options': dict({ }), 'original_device_class': None, @@ -19386,6 +19728,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l2', 'options': dict({ }), 'original_device_class': None, @@ -19434,6 +19777,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l3', 'options': dict({ }), 'original_device_class': None, @@ -19482,6 +19826,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -19530,6 +19875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l1', 'options': dict({ }), 'original_device_class': None, @@ -19578,6 +19924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l2', 'options': dict({ }), 'original_device_class': None, @@ -19626,6 +19973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l3', 'options': dict({ }), 'original_device_class': None, @@ -19674,6 +20022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active storage CT', 'options': dict({ }), 'original_device_class': None, @@ -19722,6 +20071,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active storage CT l1', 'options': dict({ }), 'original_device_class': None, @@ -19770,6 +20120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active storage CT l2', 'options': dict({ }), 'original_device_class': None, @@ -19818,6 +20169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active storage CT l3', 'options': dict({ }), 'original_device_class': None, @@ -19872,6 +20224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT', 'options': dict({ }), 'original_device_class': , @@ -19932,6 +20285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l1', 'options': dict({ }), 'original_device_class': , @@ -19992,6 +20346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l2', 'options': dict({ }), 'original_device_class': , @@ -20052,6 +20407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l3', 'options': dict({ }), 'original_device_class': , @@ -20112,6 +20468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': , @@ -20172,6 +20529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l1', 'options': dict({ }), 'original_device_class': , @@ -20232,6 +20590,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l2', 'options': dict({ }), 'original_device_class': , @@ -20292,6 +20651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l3', 'options': dict({ }), 'original_device_class': , @@ -20352,6 +20712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status storage CT', 'options': dict({ }), 'original_device_class': , @@ -20412,6 +20773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status storage CT l1', 'options': dict({ }), 'original_device_class': , @@ -20472,6 +20834,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status storage CT l2', 'options': dict({ }), 'original_device_class': , @@ -20532,6 +20895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status storage CT l3', 'options': dict({ }), 'original_device_class': , @@ -20588,6 +20952,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -20647,6 +21012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -20706,6 +21072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -20765,6 +21132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -20824,6 +21192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -20879,6 +21248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -20934,6 +21304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -20989,6 +21360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21044,6 +21416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21099,6 +21472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21154,6 +21528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21209,6 +21584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21264,6 +21640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor storage CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21319,6 +21696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor storage CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21374,6 +21752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor storage CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21429,6 +21808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor storage CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21484,6 +21864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -21543,6 +21924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -21602,6 +21984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -21661,6 +22044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -21720,6 +22104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21776,6 +22161,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserve battery level', 'options': dict({ }), 'original_device_class': , @@ -21829,6 +22215,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -21888,6 +22275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -21947,6 +22335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -22006,6 +22395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -22065,6 +22455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22124,6 +22515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22183,6 +22575,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22242,6 +22635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22301,6 +22695,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22360,6 +22755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22419,6 +22815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22478,6 +22875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22537,6 +22935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage storage CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22596,6 +22995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage storage CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22655,6 +23055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage storage CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22714,6 +23115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage storage CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22773,6 +23175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -22829,6 +23232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -22885,6 +23289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -22941,6 +23346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -22997,6 +23403,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23053,6 +23460,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23109,6 +23517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -23165,6 +23574,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23221,6 +23631,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23275,6 +23686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -23326,6 +23738,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23385,6 +23798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -23441,6 +23855,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23497,6 +23912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23556,6 +23972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23615,6 +24032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23674,6 +24092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23733,6 +24152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23792,6 +24212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23851,6 +24272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23910,6 +24332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current net power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -23969,6 +24392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24028,6 +24452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24087,6 +24512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24146,6 +24572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24205,6 +24632,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24264,6 +24692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24323,6 +24752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24382,6 +24812,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -24439,6 +24870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -24495,6 +24927,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -24551,6 +24984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -24607,6 +25041,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption last seven days l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -24665,6 +25100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -24724,6 +25160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -24783,6 +25220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -24842,6 +25280,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption today l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -24899,6 +25338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -24955,6 +25395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25011,6 +25452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25067,6 +25509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25125,6 +25568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -25184,6 +25628,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -25243,6 +25688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -25302,6 +25748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -25361,6 +25808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25417,6 +25865,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25473,6 +25922,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25529,6 +25979,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25585,6 +26036,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25641,6 +26093,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25697,6 +26150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25753,6 +26207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -25809,6 +26264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -25868,6 +26324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -25927,6 +26384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -25986,6 +26444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26045,6 +26504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26104,6 +26564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26163,6 +26624,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26222,6 +26684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26281,6 +26744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26340,6 +26804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26399,6 +26864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26458,6 +26924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26517,6 +26984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26576,6 +27044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26635,6 +27104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26694,6 +27164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy consumption l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26753,6 +27224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26812,6 +27284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26871,6 +27344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26930,6 +27404,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime net energy production l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -26987,6 +27462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT', 'options': dict({ }), 'original_device_class': None, @@ -27035,6 +27511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l1', 'options': dict({ }), 'original_device_class': None, @@ -27083,6 +27560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l2', 'options': dict({ }), 'original_device_class': None, @@ -27131,6 +27609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active net consumption CT l3', 'options': dict({ }), 'original_device_class': None, @@ -27179,6 +27658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -27227,6 +27707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l1', 'options': dict({ }), 'original_device_class': None, @@ -27275,6 +27756,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l2', 'options': dict({ }), 'original_device_class': None, @@ -27323,6 +27805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT l3', 'options': dict({ }), 'original_device_class': None, @@ -27377,6 +27860,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT', 'options': dict({ }), 'original_device_class': , @@ -27437,6 +27921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l1', 'options': dict({ }), 'original_device_class': , @@ -27497,6 +27982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l2', 'options': dict({ }), 'original_device_class': , @@ -27557,6 +28043,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status net consumption CT l3', 'options': dict({ }), 'original_device_class': , @@ -27617,6 +28104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': , @@ -27677,6 +28165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l1', 'options': dict({ }), 'original_device_class': , @@ -27737,6 +28226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l2', 'options': dict({ }), 'original_device_class': , @@ -27797,6 +28287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT l3', 'options': dict({ }), 'original_device_class': , @@ -27853,6 +28344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -27912,6 +28404,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -27971,6 +28464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -28030,6 +28524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net consumption CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -28089,6 +28584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28144,6 +28640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28199,6 +28696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28254,6 +28752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28309,6 +28808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28364,6 +28864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28419,6 +28920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28474,6 +28976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -28529,6 +29032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -28588,6 +29092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -28647,6 +29152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -28706,6 +29212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -28765,6 +29272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -28824,6 +29332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -28883,6 +29392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -28942,6 +29452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage net consumption CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -29001,6 +29512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -29060,6 +29572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -29119,6 +29632,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -29178,6 +29692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT l3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -29237,6 +29752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -29293,6 +29809,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29349,6 +29866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29405,6 +29923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29461,6 +29980,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29517,6 +30037,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29573,6 +30094,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -29629,6 +30151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29685,6 +30208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -29739,6 +30263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -29790,6 +30315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -29849,6 +30375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -29905,6 +30432,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -29961,6 +30489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balanced net power consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30020,6 +30549,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30077,6 +30607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -30135,6 +30666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -30194,6 +30726,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -30250,6 +30783,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime balanced net energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30309,6 +30843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30366,6 +30901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter status flags active production CT', 'options': dict({ }), 'original_device_class': None, @@ -30420,6 +30956,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering status production CT', 'options': dict({ }), 'original_device_class': , @@ -30476,6 +31013,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -30531,6 +31069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production CT current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30590,6 +31129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage production CT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -30649,6 +31189,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -30705,6 +31246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30761,6 +31303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30817,6 +31360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30873,6 +31417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30929,6 +31474,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production since previous report', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -30985,6 +31531,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -31041,6 +31588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -31097,6 +31645,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last report duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -31151,6 +31700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last reported', 'options': dict({ }), 'original_device_class': , @@ -31202,6 +31752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -31261,6 +31812,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -31317,6 +31869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, diff --git a/tests/components/enphase_envoy/snapshots/test_switch.ambr b/tests/components/enphase_envoy/snapshots/test_switch.ambr index 2a00e46b6af..ee30dfc76fc 100644 --- a/tests/components/enphase_envoy/snapshots/test_switch.ambr +++ b/tests/components/enphase_envoy/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge from grid', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge from grid', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid enabled', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/esphome/test_analytics.py b/tests/components/esphome/test_analytics.py index f4de75b2ee0..1ede9d76ea0 100644 --- a/tests/components/esphome/test_analytics.py +++ b/tests/components/esphome/test_analytics.py @@ -1,7 +1,5 @@ """Tests for analytics platform.""" -import pytest - from homeassistant.components.analytics import async_devices_payload from homeassistant.components.esphome import DOMAIN from homeassistant.core import HomeAssistant @@ -11,7 +9,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry -@pytest.mark.asyncio async def test_analytics( hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: diff --git a/tests/components/essent/snapshots/test_sensor.ambr b/tests/components/essent/snapshots/test_sensor.ambr index 31c02998f44..cec293d41a2 100644 --- a/tests/components/essent/snapshots/test_sensor.ambr +++ b/tests/components/essent/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average electricity price today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current electricity market price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current electricity price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current electricity price excl. VAT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current electricity purchasing fee', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current electricity tax', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current electricity VAT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current gas market price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current gas price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current gas price excl. VAT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current gas purchasing fee', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -638,6 +649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current gas tax', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -694,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current gas VAT', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -750,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest electricity price today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -806,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lowest electricity price today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -862,6 +877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next electricity price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -918,6 +934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next gas price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, diff --git a/tests/components/essent/test_sensor.py b/tests/components/essent/test_sensor.py index ce20518b527..db3c4c4cce2 100644 --- a/tests/components/essent/test_sensor.py +++ b/tests/components/essent/test_sensor.py @@ -74,5 +74,5 @@ async def test_sensor_updates_on_hour_tick( assert ( hass.states.get("sensor.essent_current_electricity_market_price").state - == "0.10417" + == "0.24535" ) diff --git a/tests/components/fan/test_condition.py b/tests/components/fan/test_condition.py new file mode 100644 index 00000000000..31c46f2fa70 --- /dev/null +++ b/tests/components/fan/test_condition.py @@ -0,0 +1,174 @@ +"""Test fan conditions.""" + +from typing import Any + +import pytest + +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant + +from tests.components import ( + ConditionStateDescription, + assert_condition_gated_by_labs_flag, + create_target_condition, + parametrize_condition_states_all, + parametrize_condition_states_any, + parametrize_target_entities, + set_or_remove_state, + target_entities, +) + + +@pytest.fixture +async def target_fans(hass: HomeAssistant) -> list[str]: + """Create multiple fan entities associated with different targets.""" + return (await target_entities(hass, "fan"))["included"] + + +@pytest.fixture +async def target_switches(hass: HomeAssistant) -> list[str]: + """Create multiple switch entities associated with different targets.""" + return (await target_entities(hass, "switch"))["included"] + + +@pytest.mark.parametrize( + "condition", + [ + "fan.is_off", + "fan.is_on", + ], +) +async def test_fan_conditions_gated_by_labs_flag( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str +) -> None: + """Test the fan conditions are gated by the labs flag.""" + await assert_condition_gated_by_labs_flag(hass, caplog, condition) + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("fan"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_any( + condition="fan.is_on", + target_states=[STATE_ON], + other_states=[STATE_OFF], + ), + *parametrize_condition_states_any( + condition="fan.is_off", + target_states=[STATE_OFF], + other_states=[STATE_ON], + ), + ], +) +async def test_fan_state_condition_behavior_any( + hass: HomeAssistant, + target_fans: list[str], + target_switches: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the fan state condition with the 'any' behavior.""" + other_entity_ids = set(target_fans) - {entity_id} + + # Set all fans, including the tested fan, to the initial state + for eid in target_fans: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="any", + ) + + # Set state for switches to ensure that they don't impact the condition + for state in states: + for eid in target_switches: + set_or_remove_state(hass, eid, state["included"]) + await hass.async_block_till_done() + assert condition(hass) is False + + for state in states: + included_state = state["included"] + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + # Check if changing other fans also passes the condition + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("fan"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_all( + condition="fan.is_on", + target_states=[STATE_ON], + other_states=[STATE_OFF], + ), + *parametrize_condition_states_all( + condition="fan.is_off", + target_states=[STATE_OFF], + other_states=[STATE_ON], + ), + ], +) +async def test_fan_state_condition_behavior_all( + hass: HomeAssistant, + target_fans: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the fan state condition with the 'all' behavior.""" + # Set state for two switches to ensure that they don't impact the condition + hass.states.async_set("switch.label_switch_1", STATE_OFF) + hass.states.async_set("switch.label_switch_2", STATE_ON) + + other_entity_ids = set(target_fans) - {entity_id} + + # Set all fans, including the tested fan, to the initial state + for eid in target_fans: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="all", + ) + + for state in states: + included_state = state["included"] + + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true_first_entity"] + + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + + assert condition(hass) == state["condition_true"] diff --git a/tests/components/fan/test_device_action.py b/tests/components/fan/test_device_action.py index 647e45374ac..747c75ed754 100644 --- a/tests/components/fan/test_device_action.py +++ b/tests/components/fan/test_device_action.py @@ -19,11 +19,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/fan/test_device_condition.py b/tests/components/fan/test_device_condition.py index da48f3223af..4b2ffad2812 100644 --- a/tests/components/fan/test_device_condition.py +++ b/tests/components/fan/test_device_condition.py @@ -15,11 +15,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/fan/test_device_trigger.py b/tests/components/fan/test_device_trigger.py index 800412fc9d4..d11078d9863 100644 --- a/tests/components/fan/test_device_trigger.py +++ b/tests/components/fan/test_device_trigger.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/fan/test_trigger.py b/tests/components/fan/test_trigger.py index dbc412696d2..b197733306c 100644 --- a/tests/components/fan/test_trigger.py +++ b/tests/components/fan/test_trigger.py @@ -1,8 +1,6 @@ """Test fan trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -10,7 +8,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, STATE_OFF, STATE_ from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -19,21 +17,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_fans(hass: HomeAssistant) -> list[str]: """Create multiple fan entities associated with different targets.""" @@ -60,7 +43,7 @@ async def test_fan_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("fan"), @@ -89,7 +72,7 @@ async def test_fan_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the fan state trigger fires when any fan state changes to a specific state.""" other_entity_ids = set(target_fans) - {entity_id} @@ -118,7 +101,7 @@ async def test_fan_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("fan"), @@ -147,7 +130,7 @@ async def test_fan_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the fan state trigger fires when the first fan changes to a specific state.""" other_entity_ids = set(target_fans) - {entity_id} @@ -175,7 +158,7 @@ async def test_fan_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("fan"), @@ -204,7 +187,7 @@ async def test_fan_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the fan state trigger fires when the last fan changes to a specific state.""" other_entity_ids = set(target_fans) - {entity_id} diff --git a/tests/components/filesize/snapshots/test_sensor.ambr b/tests/components/filesize/snapshots/test_sensor.ambr index 10eaa915616..786301e12de 100644 --- a/tests/components/filesize/snapshots/test_sensor.ambr +++ b/tests/components/filesize/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Created', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last updated', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Size in bytes', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/filter/test_sensor.py b/tests/components/filter/test_sensor.py index 22db1c3cec2..27d0fa23e3f 100644 --- a/tests/components/filter/test_sensor.py +++ b/tests/components/filter/test_sensor.py @@ -49,11 +49,6 @@ from homeassistant.util import dt as dt_util from tests.common import MockConfigEntry, assert_setup_component, get_fixture_path -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(name="values") def values_fixture() -> list[State]: """Fixture for a list of test States.""" diff --git a/tests/components/fing/snapshots/test_device_tracker.ambr b/tests/components/fing/snapshots/test_device_tracker.ambr index cf56171c26e..c019a87132a 100644 --- a/tests/components/fing/snapshots/test_device_tracker.ambr +++ b/tests/components/fing/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FreeBSD router', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PC_HOME', 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Samsung The Frame 55', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/firefly_iii/snapshots/test_sensor.ambr b/tests/components/firefly_iii/snapshots/test_sensor.ambr index efcbec9fdc4..9bea173aadc 100644 --- a/tests/components/firefly_iii/snapshots/test_sensor.ambr +++ b/tests/components/firefly_iii/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Budget', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Balance', 'options': dict({ }), 'original_device_class': , @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Role', 'options': dict({ }), 'original_device_class': None, @@ -174,6 +177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Type', 'options': dict({ }), 'original_device_class': None, @@ -225,6 +229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Earned/Spent', 'options': dict({ }), 'original_device_class': , @@ -278,6 +283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Balance', 'options': dict({ }), 'original_device_class': , @@ -329,6 +335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Role', 'options': dict({ }), 'original_device_class': None, @@ -377,6 +384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Type', 'options': dict({ }), 'original_device_class': None, @@ -428,6 +436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Balance', 'options': dict({ }), 'original_device_class': , @@ -479,6 +488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Role', 'options': dict({ }), 'original_device_class': None, @@ -527,6 +537,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Account Type', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/firefly_iii/test_sensor.py b/tests/components/firefly_iii/test_sensor.py index bcc4907051a..1408c61c1fc 100644 --- a/tests/components/firefly_iii/test_sensor.py +++ b/tests/components/firefly_iii/test_sensor.py @@ -53,8 +53,8 @@ async def test_refresh_exceptions( hass: HomeAssistant, mock_firefly_client: AsyncMock, mock_config_entry: MockConfigEntry, - freezer: FrozenDateTimeFactory, exception: Exception, + freezer: FrozenDateTimeFactory, ) -> None: """Test entities go unavailable after coordinator refresh failures.""" await setup_integration(hass, mock_config_entry) @@ -64,7 +64,7 @@ async def test_refresh_exceptions( freezer.tick(DEFAULT_SCAN_INTERVAL) async_fire_time_changed(hass, dt_util.utcnow()) - await hass.async_block_till_done() + await hass.async_block_till_done(wait_background_tasks=True) state = hass.states.get("sensor.credit_card_account_balance") assert state is not None diff --git a/tests/components/fitbit/snapshots/test_sensor.ambr b/tests/components/fitbit/snapshots/test_sensor.ambr index 068df25454d..d990996d089 100644 --- a/tests/components/fitbit/snapshots/test_sensor.ambr +++ b/tests/components/fitbit/snapshots/test_sensor.ambr @@ -281,7 +281,7 @@ 'attribution': 'Data provided by Fitbit.com', 'device_class': 'duration', 'friendly_name': 'First L. Sleep time in bed', - 'icon': 'mdi:hotel', + 'icon': 'mdi:bed', 'state_class': , 'unit_of_measurement': , }), diff --git a/tests/components/flexit_bacnet/snapshots/test_binary_sensor.ambr b/tests/components/flexit_bacnet/snapshots/test_binary_sensor.ambr index d8408a63aa6..429fdaa5cc2 100644 --- a/tests/components/flexit_bacnet/snapshots/test_binary_sensor.ambr +++ b/tests/components/flexit_bacnet/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air filter polluted', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/flexit_bacnet/snapshots/test_climate.ambr b/tests/components/flexit_bacnet/snapshots/test_climate.ambr index a58927be917..6e74e7da686 100644 --- a/tests/components/flexit_bacnet/snapshots/test_climate.ambr +++ b/tests/components/flexit_bacnet/snapshots/test_climate.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/flexit_bacnet/snapshots/test_number.ambr b/tests/components/flexit_bacnet/snapshots/test_number.ambr index 6a307a9b463..83cab289340 100644 --- a/tests/components/flexit_bacnet/snapshots/test_number.ambr +++ b/tests/components/flexit_bacnet/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away extract fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away supply fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooker hood extract fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooker hood supply fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -261,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fireplace extract fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fireplace mode runtime', 'options': dict({ }), 'original_device_class': , @@ -379,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fireplace supply fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -438,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High extract fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -497,6 +505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High supply fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -556,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Home extract fan setpoint', 'options': dict({ }), 'original_device_class': , @@ -615,6 +625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Home supply fan setpoint', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/flexit_bacnet/snapshots/test_sensor.ambr b/tests/components/flexit_bacnet/snapshots/test_sensor.ambr index 8236540654d..0fa94c05a5e 100644 --- a/tests/components/flexit_bacnet/snapshots/test_sensor.ambr +++ b/tests/components/flexit_bacnet/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air filter operating time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electric heater power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exhaust air fan', 'options': dict({ }), 'original_device_class': None, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exhaust air fan control signal', 'options': dict({ }), 'original_device_class': None, @@ -234,6 +238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exhaust air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -290,6 +295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extract air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -346,6 +352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fireplace ventilation remaining duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -402,6 +409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heat exchanger efficiency', 'options': dict({ }), 'original_device_class': None, @@ -454,6 +462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heat exchanger speed', 'options': dict({ }), 'original_device_class': None, @@ -506,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -562,6 +572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rapid ventilation remaining duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -618,6 +629,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -674,6 +686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply air fan', 'options': dict({ }), 'original_device_class': None, @@ -726,6 +739,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply air fan control signal', 'options': dict({ }), 'original_device_class': None, @@ -778,6 +792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/flexit_bacnet/snapshots/test_switch.ambr b/tests/components/flexit_bacnet/snapshots/test_switch.ambr index 6ac6f904758..a822cff1c6f 100644 --- a/tests/components/flexit_bacnet/snapshots/test_switch.ambr +++ b/tests/components/flexit_bacnet/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooker hood mode', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electric heater', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fireplace mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/fluss/__init__.py b/tests/components/fluss/__init__.py index 1849ed37655..6df50f8bd60 100644 --- a/tests/components/fluss/__init__.py +++ b/tests/components/fluss/__init__.py @@ -52,7 +52,6 @@ async def test_async_setup_entry_errors( assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR -@pytest.mark.asyncio async def test_async_setup_entry_success( hass: HomeAssistant, mock_config_entry: MagicMock, @@ -67,7 +66,6 @@ async def test_async_setup_entry_success( ) -@pytest.mark.asyncio async def test_async_unload_entry( hass: HomeAssistant, mock_config_entry: MagicMock, @@ -87,7 +85,6 @@ async def test_async_unload_entry( assert mock_config_entry.state is ConfigEntryState.NOT_LOADED -@pytest.mark.asyncio async def test_platforms_forwarded( hass: HomeAssistant, mock_config_entry: MagicMock, diff --git a/tests/components/fluss/snapshots/test_button.ambr b/tests/components/fluss/snapshots/test_button.ambr index 18d9da96b24..cde9f997f1d 100644 --- a/tests/components/fluss/snapshots/test_button.ambr +++ b/tests/components/fluss/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/folder_watcher/snapshots/test_event.ambr b/tests/components/folder_watcher/snapshots/test_event.ambr index 1514a9121c6..22eb3ccc2b6 100644 --- a/tests/components/folder_watcher/snapshots/test_event.ambr +++ b/tests/components/folder_watcher/snapshots/test_event.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/foscam/snapshots/test_number.ambr b/tests/components/foscam/snapshots/test_number.ambr index 74294c7306a..445113f3fc7 100644 --- a/tests/components/foscam/snapshots/test_number.ambr +++ b/tests/components/foscam/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device volume', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speak volume', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/foscam/snapshots/test_switch.ambr b/tests/components/foscam/snapshots/test_switch.ambr index 0945b657468..5c81388d573 100644 --- a/tests/components/foscam/snapshots/test_switch.ambr +++ b/tests/components/foscam/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car detection', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Human detection', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Infrared mode', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mirror', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pet detection', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren alarm', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep mode', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume muted', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'White light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr b/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr index 599f701e8d1..ad5bbe18e84 100644 --- a/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr +++ b/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/fressnapf_tracker/snapshots/test_device_tracker.ambr b/tests/components/fressnapf_tracker/snapshots/test_device_tracker.ambr index c8b45d4599d..30cd598fe04 100644 --- a/tests/components/fressnapf_tracker/snapshots/test_device_tracker.ambr +++ b/tests/components/fressnapf_tracker/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fressnapf_tracker/snapshots/test_light.ambr b/tests/components/fressnapf_tracker/snapshots/test_light.ambr index 81f76a0fec9..ccd4549faa3 100644 --- a/tests/components/fressnapf_tracker/snapshots/test_light.ambr +++ b/tests/components/fressnapf_tracker/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flashlight', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fressnapf_tracker/snapshots/test_sensor.ambr b/tests/components/fressnapf_tracker/snapshots/test_sensor.ambr index 042a34fb76d..2109c37e254 100644 --- a/tests/components/fressnapf_tracker/snapshots/test_sensor.ambr +++ b/tests/components/fressnapf_tracker/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/fressnapf_tracker/snapshots/test_switch.ambr b/tests/components/fressnapf_tracker/snapshots/test_switch.ambr index 7fbe4edede8..96b743119ef 100644 --- a/tests/components/fressnapf_tracker/snapshots/test_switch.ambr +++ b/tests/components/fressnapf_tracker/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/fressnapf_tracker/test_config_flow.py b/tests/components/fressnapf_tracker/test_config_flow.py index 295476ba6e9..d789a889f38 100644 --- a/tests/components/fressnapf_tracker/test_config_flow.py +++ b/tests/components/fressnapf_tracker/test_config_flow.py @@ -50,7 +50,7 @@ async def test_user_flow_success( # Submit SMS code result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.CREATE_ENTRY @@ -107,7 +107,7 @@ async def test_user_flow_request_sms_code_errors( result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.CREATE_ENTRY @@ -142,7 +142,7 @@ async def test_user_flow_verify_phone_number_errors( result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 999999}, + {CONF_SMS_CODE: "999999"}, ) assert result["type"] is FlowResultType.FORM @@ -153,7 +153,7 @@ async def test_user_flow_verify_phone_number_errors( mock_auth_client.verify_phone_number.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.CREATE_ENTRY @@ -246,7 +246,7 @@ async def test_reauth_reconfigure_flow( # Submit SMS code result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.ABORT @@ -311,7 +311,7 @@ async def test_reauth_reconfigure_flow_invalid_phone_number( result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.ABORT @@ -358,7 +358,7 @@ async def test_reauth_reconfigure_flow_invalid_sms_code( result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 999999}, + {CONF_SMS_CODE: "999999"}, ) assert result["type"] is FlowResultType.FORM @@ -369,7 +369,7 @@ async def test_reauth_reconfigure_flow_invalid_sms_code( mock_auth_client.verify_phone_number.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.ABORT @@ -436,7 +436,7 @@ async def test_reauth_reconfigure_flow_invalid_user_id( result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_SMS_CODE: 123456}, + {CONF_SMS_CODE: "0123456"}, ) assert result["type"] is FlowResultType.ABORT diff --git a/tests/components/fritz/snapshots/test_button.ambr b/tests/components/fritz/snapshots/test_button.ambr index ac222fa72d3..382c88403ba 100644 --- a/tests/components/fritz/snapshots/test_button.ambr +++ b/tests/components/fritz/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleanup', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware update', 'options': dict({ }), 'original_device_class': , @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reconnect', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -208,23 +212,24 @@ 'domain': 'button', 'entity_category': None, 'entity_id': 'button.printer_wake_on_lan', - 'has_entity_name': False, + 'has_entity_name': True, 'hidden_by': None, 'icon': None, 'id': , 'labels': set({ }), 'name': None, + 'object_id_base': 'Wake on LAN', 'options': dict({ }), 'original_device_class': None, - 'original_icon': 'mdi:lan-pending', - 'original_name': 'printer Wake on LAN', + 'original_icon': None, + 'original_name': 'Wake on LAN', 'platform': 'fritz', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'wake_on_lan', 'unique_id': 'AA:BB:CC:00:11:22_wake_on_lan', 'unit_of_measurement': None, }) @@ -233,7 +238,6 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'friendly_name': 'printer Wake on LAN', - 'icon': 'mdi:lan-pending', }), 'context': , 'entity_id': 'button.printer_wake_on_lan', diff --git a/tests/components/fritz/snapshots/test_sensor.ambr b/tests/components/fritz/snapshots/test_sensor.ambr index ae3bf6d6889..4882deed76f 100644 --- a/tests/components/fritz/snapshots/test_sensor.ambr +++ b/tests/components/fritz/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection uptime', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Download throughput', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -125,6 +127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External IP', 'options': dict({ }), 'original_device_class': None, @@ -173,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External IPv6', 'options': dict({ }), 'original_device_class': None, @@ -223,6 +227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GB received', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -279,6 +284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GB sent', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -333,6 +339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -382,6 +389,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link download noise margin', 'options': dict({ }), 'original_device_class': None, @@ -431,6 +439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link download power attenuation', 'options': dict({ }), 'original_device_class': None, @@ -480,6 +489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link download throughput', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -533,6 +543,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link upload noise margin', 'options': dict({ }), 'original_device_class': None, @@ -582,6 +593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link upload power attenuation', 'options': dict({ }), 'original_device_class': None, @@ -631,6 +643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link upload throughput', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -684,6 +697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max connection download throughput', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -737,6 +751,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max connection upload throughput', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -792,6 +807,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upload throughput', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -848,6 +864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/fritz/snapshots/test_switch.ambr b/tests/components/fritz/snapshots/test_switch.ambr index 08046c988d6..0124c5f944e 100644 --- a/tests/components/fritz/snapshots/test_switch.ambr +++ b/tests/components/fritz/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi WiFi (2.4Ghz)', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi WiFi (5Ghz)', 'options': dict({ }), 'original_device_class': None, @@ -111,23 +113,24 @@ 'domain': 'switch', 'entity_category': , 'entity_id': 'switch.printer_internet_access', - 'has_entity_name': False, + 'has_entity_name': True, 'hidden_by': None, 'icon': None, 'id': , 'labels': set({ }), 'name': None, + 'object_id_base': 'Internet access', 'options': dict({ }), 'original_device_class': None, - 'original_icon': 'mdi:router-wireless-settings', - 'original_name': 'printer Internet Access', + 'original_icon': None, + 'original_name': 'Internet access', 'platform': 'fritz', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'internet_access', 'unique_id': 'AA:BB:CC:00:11:22_internet_access', 'unit_of_measurement': None, }) @@ -135,8 +138,7 @@ # name: test_switch_setup[fc_data0][switch.printer_internet_access-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'printer Internet Access', - 'icon': 'mdi:router-wireless-settings', + 'friendly_name': 'printer Internet access', }), 'context': , 'entity_id': 'switch.printer_internet_access', @@ -167,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi WiFi', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi WiFi2', 'options': dict({ }), 'original_device_class': None, @@ -258,23 +262,24 @@ 'domain': 'switch', 'entity_category': , 'entity_id': 'switch.printer_internet_access', - 'has_entity_name': False, + 'has_entity_name': True, 'hidden_by': None, 'icon': None, 'id': , 'labels': set({ }), 'name': None, + 'object_id_base': 'Internet access', 'options': dict({ }), 'original_device_class': None, - 'original_icon': 'mdi:router-wireless-settings', - 'original_name': 'printer Internet Access', + 'original_icon': None, + 'original_name': 'Internet access', 'platform': 'fritz', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'internet_access', 'unique_id': 'AA:BB:CC:00:11:22_internet_access', 'unit_of_measurement': None, }) @@ -282,8 +287,7 @@ # name: test_switch_setup[fc_data1][switch.printer_internet_access-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'printer Internet Access', - 'icon': 'mdi:router-wireless-settings', + 'friendly_name': 'printer Internet access', }), 'context': , 'entity_id': 'switch.printer_internet_access', @@ -314,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi WiFi (2.4Ghz)', 'options': dict({ }), 'original_device_class': None, @@ -363,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi WiFi+ (5Ghz)', 'options': dict({ }), 'original_device_class': None, @@ -405,23 +411,24 @@ 'domain': 'switch', 'entity_category': , 'entity_id': 'switch.printer_internet_access', - 'has_entity_name': False, + 'has_entity_name': True, 'hidden_by': None, 'icon': None, 'id': , 'labels': set({ }), 'name': None, + 'object_id_base': 'Internet access', 'options': dict({ }), 'original_device_class': None, - 'original_icon': 'mdi:router-wireless-settings', - 'original_name': 'printer Internet Access', + 'original_icon': None, + 'original_name': 'Internet access', 'platform': 'fritz', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'internet_access', 'unique_id': 'AA:BB:CC:00:11:22_internet_access', 'unit_of_measurement': None, }) @@ -429,8 +436,7 @@ # name: test_switch_setup[fc_data2][switch.printer_internet_access-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'printer Internet Access', - 'icon': 'mdi:router-wireless-settings', + 'friendly_name': 'printer Internet access', }), 'context': , 'entity_id': 'switch.printer_internet_access', @@ -461,6 +467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Call deflection 0', 'options': dict({ }), 'original_device_class': None, @@ -516,6 +523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mock Title Wi-Fi MyWifi', 'options': dict({ }), 'original_device_class': None, @@ -558,23 +566,24 @@ 'domain': 'switch', 'entity_category': , 'entity_id': 'switch.printer_internet_access', - 'has_entity_name': False, + 'has_entity_name': True, 'hidden_by': None, 'icon': None, 'id': , 'labels': set({ }), 'name': None, + 'object_id_base': 'Internet access', 'options': dict({ }), 'original_device_class': None, - 'original_icon': 'mdi:router-wireless-settings', - 'original_name': 'printer Internet Access', + 'original_icon': None, + 'original_name': 'Internet access', 'platform': 'fritz', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'internet_access', 'unique_id': 'AA:BB:CC:00:11:22_internet_access', 'unit_of_measurement': None, }) @@ -582,8 +591,7 @@ # name: test_switch_setup[fc_data3][switch.printer_internet_access-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'printer Internet Access', - 'icon': 'mdi:router-wireless-settings', + 'friendly_name': 'printer Internet access', }), 'context': , 'entity_id': 'switch.printer_internet_access', diff --git a/tests/components/fritz/snapshots/test_update.ambr b/tests/components/fritz/snapshots/test_update.ambr index ee683cc492f..d441896dfa3 100644 --- a/tests/components/fritz/snapshots/test_update.ambr +++ b/tests/components/fritz/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FRITZ!OS', 'options': dict({ }), 'original_device_class': None, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FRITZ!OS', 'options': dict({ }), 'original_device_class': None, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FRITZ!OS', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fritzbox/snapshots/test_binary_sensor.ambr b/tests/components/fritzbox/snapshots/test_binary_sensor.ambr index 01d483fca2d..0dcc7ca3806 100644 --- a/tests/components/fritzbox/snapshots/test_binary_sensor.ambr +++ b/tests/components/fritzbox/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button lock on device', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button lock via UI', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Holiday mode', 'options': dict({ }), 'original_device_class': None, @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Open window detected', 'options': dict({ }), 'original_device_class': None, @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Summer mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fritzbox/snapshots/test_button.ambr b/tests/components/fritzbox/snapshots/test_button.ambr index fc5285cddc6..a42816271e7 100644 --- a/tests/components/fritzbox/snapshots/test_button.ambr +++ b/tests/components/fritzbox/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fritzbox/snapshots/test_climate.ambr b/tests/components/fritzbox/snapshots/test_climate.ambr index 8a0e47a4a24..24544520c42 100644 --- a/tests/components/fritzbox/snapshots/test_climate.ambr +++ b/tests/components/fritzbox/snapshots/test_climate.ambr @@ -32,6 +32,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fritzbox/snapshots/test_cover.ambr b/tests/components/fritzbox/snapshots/test_cover.ambr index 6138086e140..f4b17350fd2 100644 --- a/tests/components/fritzbox/snapshots/test_cover.ambr +++ b/tests/components/fritzbox/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/fritzbox/snapshots/test_light.ambr b/tests/components/fritzbox/snapshots/test_light.ambr index bb92b3133c6..1d0f1a88060 100644 --- a/tests/components/fritzbox/snapshots/test_light.ambr +++ b/tests/components/fritzbox/snapshots/test_light.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, @@ -112,6 +113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, @@ -190,6 +192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, @@ -248,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fritzbox/snapshots/test_sensor.ambr b/tests/components/fritzbox/snapshots/test_sensor.ambr index 061708960d4..541308e1269 100644 --- a/tests/components/fritzbox/snapshots/test_sensor.ambr +++ b/tests/components/fritzbox/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Comfort temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -179,6 +182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current scheduled preset', 'options': dict({ }), 'original_device_class': None, @@ -227,6 +231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Eco temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next scheduled change time', 'options': dict({ }), 'original_device_class': , @@ -329,6 +335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next scheduled preset', 'options': dict({ }), 'original_device_class': None, @@ -377,6 +384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next scheduled temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -432,6 +440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -488,6 +497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -541,6 +551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -594,6 +605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -650,6 +662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -706,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -762,6 +776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -818,6 +833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -874,6 +890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/fritzbox/snapshots/test_switch.ambr b/tests/components/fritzbox/snapshots/test_switch.ambr index e9d380cc85a..5163ac9d604 100644 --- a/tests/components/fritzbox/snapshots/test_switch.ambr +++ b/tests/components/fritzbox/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_name', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'fake_trigger', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fronius/snapshots/test_sensor.ambr b/tests/components/fronius/snapshots/test_sensor.ambr index 14ca17d81c1..627f298c695 100644 --- a/tests/components/fronius/snapshots/test_sensor.ambr +++ b/tests/components/fronius/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -412,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error code', 'options': dict({ }), 'original_device_class': None, @@ -559,6 +567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error message', 'options': dict({ }), 'original_device_class': , @@ -708,6 +717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -762,6 +772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter state', 'options': dict({ }), 'original_device_class': None, @@ -810,6 +821,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status code', 'options': dict({ }), 'original_device_class': None, @@ -869,6 +881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status message', 'options': dict({ }), 'original_device_class': , @@ -930,6 +943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -986,6 +1000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1042,6 +1057,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1098,6 +1114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1154,6 +1171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1210,6 +1228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1266,6 +1285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1322,6 +1342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1378,6 +1399,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency phase average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1432,6 +1454,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter location', 'options': dict({ }), 'original_device_class': None, @@ -1488,6 +1511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter location description', 'options': dict({ }), 'original_device_class': , @@ -1546,6 +1570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -1598,6 +1623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 1', 'options': dict({ }), 'original_device_class': , @@ -1650,6 +1676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 2', 'options': dict({ }), 'original_device_class': , @@ -1702,6 +1729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 3', 'options': dict({ }), 'original_device_class': , @@ -1754,6 +1782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive energy consumed', 'options': dict({ }), 'original_device_class': None, @@ -1806,6 +1835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive energy produced', 'options': dict({ }), 'original_device_class': None, @@ -1858,6 +1888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1914,6 +1945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1970,6 +2002,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2026,6 +2059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2082,6 +2116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2138,6 +2173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy minus', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2194,6 +2230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy plus', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2250,6 +2287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2306,6 +2344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2362,6 +2401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2418,6 +2458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2474,6 +2515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2530,6 +2572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2586,6 +2629,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1-2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2642,6 +2686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2698,6 +2743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2-3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2754,6 +2800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2810,6 +2857,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3-1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2864,6 +2912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter mode', 'options': dict({ }), 'original_device_class': None, @@ -2914,6 +2963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2970,6 +3020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3026,6 +3077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3082,6 +3134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3138,6 +3191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3194,6 +3248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load generated', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3250,6 +3305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power photovoltaics', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3306,6 +3362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative autonomy', 'options': dict({ }), 'original_device_class': None, @@ -3358,6 +3415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative self-consumption', 'options': dict({ }), 'original_device_class': None, @@ -3410,6 +3468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3466,6 +3525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3522,6 +3582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3576,6 +3637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Designed capacity', 'options': dict({ }), 'original_device_class': None, @@ -3625,6 +3687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum capacity', 'options': dict({ }), 'original_device_class': None, @@ -3676,6 +3739,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge', 'options': dict({ }), 'original_device_class': , @@ -3729,6 +3793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3785,6 +3850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3841,6 +3907,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3897,6 +3964,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3953,6 +4021,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4009,6 +4078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4065,6 +4135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4121,6 +4192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4175,6 +4247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error code', 'options': dict({ }), 'original_device_class': None, @@ -4322,6 +4395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error message', 'options': dict({ }), 'original_device_class': , @@ -4471,6 +4545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4525,6 +4600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter state', 'options': dict({ }), 'original_device_class': None, @@ -4573,6 +4649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status code', 'options': dict({ }), 'original_device_class': None, @@ -4632,6 +4709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status message', 'options': dict({ }), 'original_device_class': , @@ -4693,6 +4771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4749,6 +4828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4805,6 +4885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4859,6 +4940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State code', 'options': dict({ }), 'original_device_class': None, @@ -4916,6 +4998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State message', 'options': dict({ }), 'original_device_class': , @@ -4975,6 +5058,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5031,6 +5115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5087,6 +5172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5143,6 +5229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5199,6 +5286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5255,6 +5343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5311,6 +5400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5367,6 +5457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5423,6 +5514,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency phase average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5477,6 +5569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter location', 'options': dict({ }), 'original_device_class': None, @@ -5533,6 +5626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter location description', 'options': dict({ }), 'original_device_class': , @@ -5591,6 +5685,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -5643,6 +5738,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 1', 'options': dict({ }), 'original_device_class': , @@ -5695,6 +5791,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 2', 'options': dict({ }), 'original_device_class': , @@ -5747,6 +5844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 3', 'options': dict({ }), 'original_device_class': , @@ -5799,6 +5897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive energy consumed', 'options': dict({ }), 'original_device_class': None, @@ -5851,6 +5950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive energy produced', 'options': dict({ }), 'original_device_class': None, @@ -5903,6 +6003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5959,6 +6060,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6015,6 +6117,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6071,6 +6174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6127,6 +6231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6183,6 +6288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy minus', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6239,6 +6345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy plus', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6295,6 +6402,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real energy produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6351,6 +6459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6407,6 +6516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6463,6 +6573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6519,6 +6630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6575,6 +6687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6631,6 +6744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1-2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6687,6 +6801,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6743,6 +6858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2-3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6799,6 +6915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6855,6 +6972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3-1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6909,6 +7027,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter mode', 'options': dict({ }), 'original_device_class': None, @@ -6959,6 +7078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7015,6 +7135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power battery charge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7071,6 +7192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power battery discharge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7127,6 +7249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7183,6 +7306,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7239,6 +7363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7295,6 +7420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7351,6 +7477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7407,6 +7534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load generated', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7463,6 +7591,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power photovoltaics', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7519,6 +7648,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative autonomy', 'options': dict({ }), 'original_device_class': None, @@ -7571,6 +7701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative self-consumption', 'options': dict({ }), 'original_device_class': None, @@ -7623,6 +7754,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7679,6 +7811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7735,6 +7868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7791,6 +7925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7847,6 +7982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7903,6 +8039,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7959,6 +8096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy day', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8015,6 +8153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8069,6 +8208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error code', 'options': dict({ }), 'original_device_class': None, @@ -8216,6 +8356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error message', 'options': dict({ }), 'original_device_class': , @@ -8365,6 +8506,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8419,6 +8561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED color', 'options': dict({ }), 'original_device_class': None, @@ -8467,6 +8610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED state', 'options': dict({ }), 'original_device_class': None, @@ -8515,6 +8659,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status code', 'options': dict({ }), 'original_device_class': None, @@ -8574,6 +8719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status message', 'options': dict({ }), 'original_device_class': , @@ -8635,6 +8781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8691,6 +8838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8747,6 +8895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8803,6 +8952,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8859,6 +9009,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8915,6 +9066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8971,6 +9123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy day', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9027,6 +9180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9081,6 +9235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error code', 'options': dict({ }), 'original_device_class': None, @@ -9228,6 +9383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error message', 'options': dict({ }), 'original_device_class': , @@ -9377,6 +9533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9431,6 +9588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED color', 'options': dict({ }), 'original_device_class': None, @@ -9479,6 +9637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED state', 'options': dict({ }), 'original_device_class': None, @@ -9527,6 +9686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status code', 'options': dict({ }), 'original_device_class': None, @@ -9586,6 +9746,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status message', 'options': dict({ }), 'original_device_class': , @@ -9647,6 +9808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9701,6 +9863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter location', 'options': dict({ }), 'original_device_class': None, @@ -9757,6 +9920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter location description', 'options': dict({ }), 'original_device_class': , @@ -9815,6 +9979,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Real power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9871,6 +10036,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CO₂ factor', 'options': dict({ }), 'original_device_class': None, @@ -9923,6 +10089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy day', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9979,6 +10146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10035,6 +10203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid export tariff', 'options': dict({ }), 'original_device_class': None, @@ -10087,6 +10256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid import tariff', 'options': dict({ }), 'original_device_class': None, @@ -10137,6 +10307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter mode', 'options': dict({ }), 'original_device_class': None, @@ -10187,6 +10358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10243,6 +10415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10299,6 +10472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power grid import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10355,6 +10529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10411,6 +10586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10467,6 +10643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power load generated', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10523,6 +10700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power photovoltaics', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10579,6 +10757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative autonomy', 'options': dict({ }), 'original_device_class': None, @@ -10631,6 +10810,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relative self-consumption', 'options': dict({ }), 'original_device_class': None, @@ -10683,6 +10863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/fujitsu_fglair/snapshots/test_climate.ambr b/tests/components/fujitsu_fglair/snapshots/test_climate.ambr index e432d6a258a..d1dc6c8dd28 100644 --- a/tests/components/fujitsu_fglair/snapshots/test_climate.ambr +++ b/tests/components/fujitsu_fglair/snapshots/test_climate.ambr @@ -42,6 +42,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -138,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fujitsu_fglair/snapshots/test_sensor.ambr b/tests/components/fujitsu_fglair/snapshots/test_sensor.ambr index e5dcda8d1a5..c11a924bef4 100644 --- a/tests/components/fujitsu_fglair/snapshots/test_sensor.ambr +++ b/tests/components/fujitsu_fglair/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/fyta/snapshots/test_binary_sensor.ambr b/tests/components/fyta/snapshots/test_binary_sensor.ambr index 4483c9cdb86..02b98e6d2c6 100644 --- a/tests/components/fyta/snapshots/test_binary_sensor.ambr +++ b/tests/components/fyta/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light notification', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nutrition notification', 'options': dict({ }), 'original_device_class': None, @@ -165,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Productive plant', 'options': dict({ }), 'original_device_class': None, @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Repotted', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature notification', 'options': dict({ }), 'original_device_class': None, @@ -309,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': , @@ -358,6 +365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water notification', 'options': dict({ }), 'original_device_class': None, @@ -406,6 +414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -455,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light notification', 'options': dict({ }), 'original_device_class': None, @@ -503,6 +513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nutrition notification', 'options': dict({ }), 'original_device_class': None, @@ -551,6 +562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Productive plant', 'options': dict({ }), 'original_device_class': None, @@ -599,6 +611,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Repotted', 'options': dict({ }), 'original_device_class': None, @@ -647,6 +660,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature notification', 'options': dict({ }), 'original_device_class': None, @@ -695,6 +709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': , @@ -744,6 +759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water notification', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fyta/snapshots/test_image.ambr b/tests/components/fyta/snapshots/test_image.ambr index fd39c372b28..41df8584896 100644 --- a/tests/components/fyta/snapshots/test_image.ambr +++ b/tests/components/fyta/snapshots/test_image.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plant image', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User image', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plant image', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User image', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/fyta/snapshots/test_sensor.ambr b/tests/components/fyta/snapshots/test_sensor.ambr index 289927a587b..b7d4f1442e7 100644 --- a/tests/components/fyta/snapshots/test_sensor.ambr +++ b/tests/components/fyta/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last fertilized', 'options': dict({ }), 'original_device_class': , @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light state', 'options': dict({ }), 'original_device_class': , @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , @@ -310,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture state', 'options': dict({ }), 'original_device_class': , @@ -367,6 +373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next fertilization', 'options': dict({ }), 'original_device_class': , @@ -425,6 +432,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nutrients state', 'options': dict({ }), 'original_device_class': , @@ -484,6 +492,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH', 'options': dict({ }), 'original_device_class': , @@ -541,6 +550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plant state', 'options': dict({ }), 'original_device_class': , @@ -598,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salinity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -665,6 +676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salinity state', 'options': dict({ }), 'original_device_class': , @@ -722,6 +734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scientific name', 'options': dict({ }), 'original_device_class': None, @@ -772,6 +785,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -839,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature state', 'options': dict({ }), 'original_device_class': , @@ -898,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -949,6 +965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last fertilized', 'options': dict({ }), 'original_device_class': , @@ -1000,6 +1017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -1063,6 +1081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light state', 'options': dict({ }), 'original_device_class': , @@ -1122,6 +1141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , @@ -1186,6 +1206,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture state', 'options': dict({ }), 'original_device_class': , @@ -1243,6 +1264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next fertilization', 'options': dict({ }), 'original_device_class': , @@ -1301,6 +1323,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nutrients state', 'options': dict({ }), 'original_device_class': , @@ -1360,6 +1383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH', 'options': dict({ }), 'original_device_class': , @@ -1417,6 +1441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plant state', 'options': dict({ }), 'original_device_class': , @@ -1474,6 +1499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salinity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1541,6 +1567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salinity state', 'options': dict({ }), 'original_device_class': , @@ -1598,6 +1625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scientific name', 'options': dict({ }), 'original_device_class': None, @@ -1648,6 +1676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1715,6 +1744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature state', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/garages_amsterdam/snapshots/test_binary_sensor.ambr b/tests/components/garages_amsterdam/snapshots/test_binary_sensor.ambr index d70ebc38b2c..0ac0d5f0f2b 100644 --- a/tests/components/garages_amsterdam/snapshots/test_binary_sensor.ambr +++ b/tests/components/garages_amsterdam/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/garages_amsterdam/snapshots/test_sensor.ambr b/tests/components/garages_amsterdam/snapshots/test_sensor.ambr index f47d8b9788a..8ba6c7f2c98 100644 --- a/tests/components/garages_amsterdam/snapshots/test_sensor.ambr +++ b/tests/components/garages_amsterdam/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Long parking capacity', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Long parking free space', 'options': dict({ }), 'original_device_class': None, @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Short parking capacity', 'options': dict({ }), 'original_device_class': None, @@ -175,6 +178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Short parking free space', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/generic_thermostat/test_config_flow.py b/tests/components/generic_thermostat/test_config_flow.py index 561870ad3d4..9fec488d449 100644 --- a/tests/components/generic_thermostat/test_config_flow.py +++ b/tests/components/generic_thermostat/test_config_flow.py @@ -11,6 +11,7 @@ from homeassistant.components.generic_thermostat.const import ( CONF_COLD_TOLERANCE, CONF_HEATER, CONF_HOT_TOLERANCE, + CONF_KEEP_ALIVE, CONF_PRESETS, CONF_SENSOR, DOMAIN, @@ -85,6 +86,7 @@ async def test_options(hass: HomeAssistant, snapshot: SnapshotAssertion) -> None CONF_AC_MODE: False, CONF_COLD_TOLERANCE: 0.3, CONF_HOT_TOLERANCE: 0.3, + CONF_KEEP_ALIVE: {"seconds": 60}, CONF_PRESETS[PRESET_AWAY]: 20, }, title="My dehumidifier", @@ -180,3 +182,46 @@ async def test_config_flow_preset_accepts_float( "name": "My thermostat", "target_sensor": "sensor.temperature", } + + +async def test_config_flow_with_keep_alive(hass: HomeAssistant) -> None: + """Test the config flow when keep_alive is set.""" + with patch( + "homeassistant.components.generic_thermostat.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + # Keep_alive input data for test + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_NAME: "My thermostat", + CONF_HEATER: "switch.run", + CONF_SENSOR: "sensor.temperature", + CONF_AC_MODE: False, + CONF_COLD_TOLERANCE: 0.3, + CONF_HOT_TOLERANCE: 0.3, + CONF_KEEP_ALIVE: {"seconds": 60}, + }, + ) + + # Complete config flow + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_PRESETS[PRESET_AWAY]: 21, + }, + ) + + assert result["type"] == "create_entry" + + val = result["options"].get(CONF_KEEP_ALIVE) + assert val is not None + assert isinstance(val, dict) + assert val == {"seconds": 60} + + await hass.async_block_till_done() + assert len(mock_setup_entry.mock_calls) == 1 diff --git a/tests/components/geniushub/snapshots/test_binary_sensor.ambr b/tests/components/geniushub/snapshots/test_binary_sensor.ambr index 07f8ecb297d..b1f581f561a 100644 --- a/tests/components/geniushub/snapshots/test_binary_sensor.ambr +++ b/tests/components/geniushub/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Single Channel Receiver 22', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/geniushub/snapshots/test_climate.ambr b/tests/components/geniushub/snapshots/test_climate.ambr index c80e54420e7..f2c2130a987 100644 --- a/tests/components/geniushub/snapshots/test_climate.ambr +++ b/tests/components/geniushub/snapshots/test_climate.ambr @@ -30,6 +30,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bedroom', 'options': dict({ }), 'original_device_class': None, @@ -112,6 +113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ensuite', 'options': dict({ }), 'original_device_class': None, @@ -196,6 +198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Guest room', 'options': dict({ }), 'original_device_class': None, @@ -280,6 +283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hall', 'options': dict({ }), 'original_device_class': None, @@ -364,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen', 'options': dict({ }), 'original_device_class': None, @@ -447,6 +452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lounge', 'options': dict({ }), 'original_device_class': None, @@ -529,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Study', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/geniushub/snapshots/test_sensor.ambr b/tests/components/geniushub/snapshots/test_sensor.ambr index 53594845b99..d3fa2bec8a6 100644 --- a/tests/components/geniushub/snapshots/test_sensor.ambr +++ b/tests/components/geniushub/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GeniusHub Errors', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GeniusHub Information', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GeniusHub Warnings', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 11', 'options': dict({ }), 'original_device_class': , @@ -225,6 +229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 56', 'options': dict({ }), 'original_device_class': , @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 68', 'options': dict({ }), 'original_device_class': , @@ -335,6 +341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 78', 'options': dict({ }), 'original_device_class': , @@ -390,6 +397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 85', 'options': dict({ }), 'original_device_class': , @@ -445,6 +453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 88', 'options': dict({ }), 'original_device_class': , @@ -500,6 +509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 89', 'options': dict({ }), 'original_device_class': , @@ -555,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Radiator Valve 90', 'options': dict({ }), 'original_device_class': , @@ -610,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 16', 'options': dict({ }), 'original_device_class': , @@ -667,6 +679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 17', 'options': dict({ }), 'original_device_class': , @@ -724,6 +737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 18', 'options': dict({ }), 'original_device_class': , @@ -781,6 +795,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 20', 'options': dict({ }), 'original_device_class': , @@ -838,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 21', 'options': dict({ }), 'original_device_class': , @@ -895,6 +911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 50', 'options': dict({ }), 'original_device_class': , @@ -952,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room Sensor 53', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/geniushub/snapshots/test_switch.ambr b/tests/components/geniushub/snapshots/test_switch.ambr index f20717182c0..edafebbc932 100644 --- a/tests/components/geniushub/snapshots/test_switch.ambr +++ b/tests/components/geniushub/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bedroom Socket', 'options': dict({ }), 'original_device_class': , @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen Socket', 'options': dict({ }), 'original_device_class': , @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Study Socket', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/gentex_homelink/snapshots/test_event.ambr b/tests/components/gentex_homelink/snapshots/test_event.ambr index f0c6c3c8d16..0e5d757ab56 100644 --- a/tests/components/gentex_homelink/snapshots/test_event.ambr +++ b/tests/components/gentex_homelink/snapshots/test_event.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 1', 'options': dict({ }), 'original_device_class': , @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 2', 'options': dict({ }), 'original_device_class': , @@ -138,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 3', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/geo_location/test_trigger.py b/tests/components/geo_location/test_trigger.py index 0a9ad8a5b16..79a67a990bc 100644 --- a/tests/components/geo_location/test_trigger.py +++ b/tests/components/geo_location/test_trigger.py @@ -17,11 +17,6 @@ from homeassistant.setup import async_setup_component from tests.common import async_mock_service, mock_component -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture def calls(hass: HomeAssistant) -> list[ServiceCall]: """Track calls to a mock service.""" diff --git a/tests/components/gios/snapshots/test_sensor.ambr b/tests/components/gios/snapshots/test_sensor.ambr index b7ad5b2d51d..e5125b140d7 100644 --- a/tests/components/gios/snapshots/test_sensor.ambr +++ b/tests/components/gios/snapshots/test_sensor.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality index', 'options': dict({ }), 'original_device_class': , @@ -89,6 +90,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Benzene', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -201,6 +204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -265,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide index', 'options': dict({ }), 'original_device_class': , @@ -325,6 +330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen monoxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -382,6 +388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen oxides', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -438,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -502,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone index', 'options': dict({ }), 'original_device_class': , @@ -562,6 +571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -626,6 +636,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10 index', 'options': dict({ }), 'original_device_class': , @@ -686,6 +697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -750,6 +762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5 index', 'options': dict({ }), 'original_device_class': , @@ -810,6 +823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sulphur dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -874,6 +888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sulphur dioxide index', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/glances/snapshots/test_sensor.ambr b/tests/components/glances/snapshots/test_sensor.ambr index 40dd1a00cd1..c344d27e81c 100644 --- a/tests/components/glances/snapshots/test_sensor.ambr +++ b/tests/components/glances/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Containers active', 'options': dict({ }), 'original_device_class': None, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Containers CPU usage', 'options': dict({ }), 'original_device_class': None, @@ -125,6 +127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Containers memory used', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -181,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'cpu_thermal 1 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -237,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'dummy0 RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -296,6 +301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'dummy0 TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -355,6 +361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'err_temp temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -411,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'eth0 RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'eth0 TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -529,6 +538,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'lo RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -588,6 +598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'lo TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -647,6 +658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'md1 available', 'options': dict({ }), 'original_device_class': None, @@ -698,6 +710,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'md1 used', 'options': dict({ }), 'original_device_class': None, @@ -749,6 +762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'md3 available', 'options': dict({ }), 'original_device_class': None, @@ -800,6 +814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'md3 used', 'options': dict({ }), 'original_device_class': None, @@ -851,6 +866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '/media disk free', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -907,6 +923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '/media disk usage', 'options': dict({ }), 'original_device_class': None, @@ -959,6 +976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '/media disk used', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1015,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory free', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1071,6 +1090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ }), 'original_device_class': None, @@ -1123,6 +1143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory use', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1179,6 +1200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'na_temp temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1235,6 +1257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NVIDIA GeForce RTX 3080 (GPU 0) fan speed', 'options': dict({ }), 'original_device_class': None, @@ -1287,6 +1310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NVIDIA GeForce RTX 3080 (GPU 0) memory usage', 'options': dict({ }), 'original_device_class': None, @@ -1339,6 +1363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NVIDIA GeForce RTX 3080 (GPU 0) processor usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1394,6 +1419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NVIDIA GeForce RTX 3080 (GPU 0) temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1450,6 +1476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'nvme0n1 disk read', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1509,6 +1536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'nvme0n1 disk write', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1568,6 +1596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'sda disk read', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1627,6 +1656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'sda disk write', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1686,6 +1716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '/ssl disk free', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1742,6 +1773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '/ssl disk usage', 'options': dict({ }), 'original_device_class': None, @@ -1794,6 +1826,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '/ssl disk used', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1848,6 +1881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/google_air_quality/fixtures/air_quality_data.json b/tests/components/google_air_quality/fixtures/air_quality_data.json index 1f35256030d..4c2a1f929d3 100644 --- a/tests/components/google_air_quality/fixtures/air_quality_data.json +++ b/tests/components/google_air_quality/fixtures/air_quality_data.json @@ -81,6 +81,42 @@ "value": 1.2, "units": "PARTS_PER_BILLION" } + }, + { + "code": "nh3", + "displayName": "NH3", + "fullName": "Ammonia", + "concentration": { + "value": 81.41, + "units": "PARTS_PER_BILLION" + } + }, + { + "code": "no", + "displayName": "NO", + "fullName": "Nitrogen monoxide", + "concentration": { + "value": 0.62, + "units": "PARTS_PER_BILLION" + } + }, + { + "code": "nmhc", + "displayName": "NMHC", + "fullName": "Non-methane hydrocarbons", + "concentration": { + "value": 52.66, + "units": "PARTS_PER_BILLION" + } + }, + { + "code": "c6h6", + "displayName": "C6H6", + "fullName": "Benzene", + "concentration": { + "value": 0.24, + "units": "MICROGRAMS_PER_CUBIC_METER" + } } ] } diff --git a/tests/components/google_air_quality/snapshots/test_sensor.ambr b/tests/components/google_air_quality/snapshots/test_sensor.ambr index af3b27d4933..05e085e79f1 100644 --- a/tests/components/google_air_quality/snapshots/test_sensor.ambr +++ b/tests/components/google_air_quality/snapshots/test_sensor.ambr @@ -1,4 +1,112 @@ # serializer version: 1 +# name: test_sensor_snapshot[sensor.home_ammonia-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.home_ammonia', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Ammonia', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Ammonia', + 'platform': 'google_air_quality', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'ammonia', + 'unique_id': 'nh3_10.1_20.1', + 'unit_of_measurement': 'ppb', + }) +# --- +# name: test_sensor_snapshot[sensor.home_ammonia-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by Google Air Quality', + 'friendly_name': 'Home Ammonia', + 'state_class': , + 'unit_of_measurement': 'ppb', + }), + 'context': , + 'entity_id': 'sensor.home_ammonia', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '81.41', + }) +# --- +# name: test_sensor_snapshot[sensor.home_benzene-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.home_benzene', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Benzene', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Benzene', + 'platform': 'google_air_quality', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'benzene', + 'unique_id': 'c6h6_10.1_20.1', + 'unit_of_measurement': 'μg/m³', + }) +# --- +# name: test_sensor_snapshot[sensor.home_benzene-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by Google Air Quality', + 'friendly_name': 'Home Benzene', + 'state_class': , + 'unit_of_measurement': 'μg/m³', + }), + 'context': , + 'entity_id': 'sensor.home_benzene', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.24', + }) +# --- # name: test_sensor_snapshot[sensor.home_carbon_monoxide-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -22,7 +130,11 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ + 'sensor.private': dict({ + 'suggested_unit_of_measurement': 'ppm', + }), }), 'original_device_class': , 'original_icon': None, @@ -82,6 +194,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LQI (DE) category', 'options': dict({ }), 'original_device_class': , @@ -146,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LQI (DE) dominant pollutant', 'options': dict({ }), 'original_device_class': , @@ -204,16 +318,17 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Nitrogen dioxide', 'platform': 'google_air_quality', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': 'nitrogen_dioxide', + 'translation_key': None, 'unique_id': 'no2_10.1_20.1', 'unit_of_measurement': 'ppb', }) @@ -222,6 +337,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Google Air Quality', + 'device_class': 'nitrogen_dioxide', 'friendly_name': 'Home Nitrogen dioxide', 'state_class': , 'unit_of_measurement': 'ppb', @@ -234,6 +350,114 @@ 'state': '14.18', }) # --- +# name: test_sensor_snapshot[sensor.home_nitrogen_monoxide-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.home_nitrogen_monoxide', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Nitrogen monoxide', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Nitrogen monoxide', + 'platform': 'google_air_quality', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'nitrogen_monoxide', + 'unique_id': 'no_10.1_20.1', + 'unit_of_measurement': 'ppb', + }) +# --- +# name: test_sensor_snapshot[sensor.home_nitrogen_monoxide-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by Google Air Quality', + 'friendly_name': 'Home Nitrogen monoxide', + 'state_class': , + 'unit_of_measurement': 'ppb', + }), + 'context': , + 'entity_id': 'sensor.home_nitrogen_monoxide', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.62', + }) +# --- +# name: test_sensor_snapshot[sensor.home_non_methane_hydrocarbons-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.home_non_methane_hydrocarbons', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Non-methane hydrocarbons', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Non-methane hydrocarbons', + 'platform': 'google_air_quality', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'non_methane_hydrocarbons', + 'unique_id': 'nmhc_10.1_20.1', + 'unit_of_measurement': 'ppb', + }) +# --- +# name: test_sensor_snapshot[sensor.home_non_methane_hydrocarbons-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Data provided by Google Air Quality', + 'friendly_name': 'Home Non-methane hydrocarbons', + 'state_class': , + 'unit_of_measurement': 'ppb', + }), + 'context': , + 'entity_id': 'sensor.home_non_methane_hydrocarbons', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '52.66', + }) +# --- # name: test_sensor_snapshot[sensor.home_ozone-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -257,6 +481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone', 'options': dict({ }), 'original_device_class': None, @@ -310,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -364,6 +590,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -418,16 +645,17 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sulphur dioxide', 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Sulphur dioxide', 'platform': 'google_air_quality', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': 'sulphur_dioxide', + 'translation_key': None, 'unique_id': 'so2_10.1_20.1', 'unit_of_measurement': 'ppb', }) @@ -436,6 +664,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Google Air Quality', + 'device_class': 'sulphur_dioxide', 'friendly_name': 'Home Sulphur dioxide', 'state_class': , 'unit_of_measurement': 'ppb', @@ -477,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UAQI category', 'options': dict({ }), 'original_device_class': , @@ -543,6 +773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UAQI dominant pollutant', 'options': dict({ }), 'original_device_class': , @@ -603,6 +834,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Universal Air Quality Index', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/google_drive/snapshots/test_sensor.ambr b/tests/components/google_drive/snapshots/test_sensor.ambr index f3f53bb0ee4..354918d1fd0 100644 --- a/tests/components/google_drive/snapshots/test_sensor.ambr +++ b/tests/components/google_drive/snapshots/test_sensor.ambr @@ -51,6 +51,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total available storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -107,6 +108,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total size of backups', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -163,6 +165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Used storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -219,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Used storage in Drive', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -275,6 +279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Used storage in Drive Trash', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/google_weather/snapshots/test_sensor.ambr b/tests/components/google_weather/snapshots/test_sensor.ambr index ceb02d99754..772d2d2e261 100644 --- a/tests/components/google_weather/snapshots/test_sensor.ambr +++ b/tests/components/google_weather/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud coverage', 'options': dict({ }), 'original_device_class': None, @@ -186,6 +189,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -242,6 +246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heat index temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -298,6 +303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -351,6 +357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -407,6 +414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation probability', 'options': dict({ }), 'original_device_class': None, @@ -459,6 +467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -515,6 +524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunderstorm probability', 'options': dict({ }), 'original_device_class': None, @@ -567,6 +577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -619,6 +630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Visibility', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -673,6 +685,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather condition', 'options': dict({ }), 'original_device_class': None, @@ -723,6 +736,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind chill temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -779,6 +793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -832,6 +847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -888,6 +904,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/google_weather/snapshots/test_weather.ambr b/tests/components/google_weather/snapshots/test_weather.ambr index e33f864ab67..86eb805fa0b 100644 --- a/tests/components/google_weather/snapshots/test_weather.ambr +++ b/tests/components/google_weather/snapshots/test_weather.ambr @@ -144,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/gree/snapshots/test_climate.ambr b/tests/components/gree/snapshots/test_climate.ambr index 5a6ce0ce5a7..0ef3c895877 100644 --- a/tests/components/gree/snapshots/test_climate.ambr +++ b/tests/components/gree/snapshots/test_climate.ambr @@ -107,6 +107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/gree/snapshots/test_switch.ambr b/tests/components/gree/snapshots/test_switch.ambr index 982afef30e8..3f83d3e6e7a 100644 --- a/tests/components/gree/snapshots/test_switch.ambr +++ b/tests/components/gree/snapshots/test_switch.ambr @@ -85,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Panel light', 'options': dict({ }), 'original_device_class': , @@ -118,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quiet mode', 'options': dict({ }), 'original_device_class': , @@ -151,6 +153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fresh air', 'options': dict({ }), 'original_device_class': , @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Xtra fan', 'options': dict({ }), 'original_device_class': , @@ -217,6 +221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/group/test_sensor.py b/tests/components/group/test_sensor.py index acbd9c44cbf..dafdbbb9c3d 100644 --- a/tests/components/group/test_sensor.py +++ b/tests/components/group/test_sensor.py @@ -41,7 +41,20 @@ from homeassistant.setup import async_setup_component from tests.common import get_fixture_path VALUES = [17, 20, 15.3] -VALUES_ERROR = [17, "string", 15.3] + +STATES_ONE_ERROR = ["17", "string", "15.3"] +STATES_ONE_MISSING = ["17", None, "15.3"] +STATES_ONE_UNKNOWN = ["17", STATE_UNKNOWN, "15.3"] +STATES_ONE_UNAVAILABLE = ["17", STATE_UNAVAILABLE, "15.3"] +STATES_ALL_ERROR = ["string", "string", "string"] +STATES_ALL_MISSING = [None, None, None] +STATES_ALL_UNKNOWN = [STATE_UNKNOWN, STATE_UNKNOWN, STATE_UNKNOWN] +STATES_ALL_UNAVAILABLE = [STATE_UNAVAILABLE, STATE_UNAVAILABLE, STATE_UNAVAILABLE] +STATES_MIX_MISSING_UNAVAILABLE_UNKNOWN = [None, STATE_UNAVAILABLE, STATE_UNKNOWN] +STATES_MIX_MISSING_UNAVAILABLE = [None, STATE_UNAVAILABLE, STATE_UNAVAILABLE] +STATES_MIX_MISSING_UNKNOWN = [None, STATE_UNKNOWN, STATE_UNKNOWN] +STATES_MIX_UNAVAILABLE_UNKNOWN = [STATE_UNAVAILABLE, STATE_UNKNOWN, STATE_UNKNOWN] + COUNT = len(VALUES) MIN_VALUE = min(VALUES) MAX_VALUE = max(VALUES) @@ -53,6 +66,18 @@ SUM_VALUE = sum(VALUES) PRODUCT_VALUE = prod(VALUES) +def set_or_remove_state( + hass: HomeAssistant, + entity_id: str, + state: str | None, +) -> None: + """Set or remove the state of an entity.""" + if state is None: + hass.states.async_remove(entity_id) + else: + hass.states.async_set(entity_id, state) + + @pytest.mark.parametrize( ("sensor_type", "result", "attributes"), [ @@ -90,7 +115,7 @@ async def test_sensors2( for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): hass.states.async_set( entity_id, - value, + str(value), { ATTR_DEVICE_CLASS: SensorDeviceClass.VOLUME, ATTR_STATE_CLASS: SensorStateClass.TOTAL, @@ -140,7 +165,7 @@ async def test_sensors_attributes_defined(hass: HomeAssistant) -> None: for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): hass.states.async_set( entity_id, - value, + str(value), { ATTR_DEVICE_CLASS: SensorDeviceClass.VOLUME, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, @@ -181,37 +206,37 @@ async def test_not_enough_sensor_value(hass: HomeAssistant) -> None: await hass.async_block_till_done() state = hass.states.get("sensor.test_max") - assert state.state == STATE_UNAVAILABLE + assert state.state == STATE_UNKNOWN assert state.attributes.get("min_entity_id") is None assert state.attributes.get("max_entity_id") is None - hass.states.async_set(entity_ids[1], VALUES[1]) + hass.states.async_set(entity_ids[1], str(VALUES[1])) await hass.async_block_till_done() state = hass.states.get("sensor.test_max") assert state.state not in [STATE_UNAVAILABLE, STATE_UNKNOWN] - assert entity_ids[1] == state.attributes.get("max_entity_id") + assert state.attributes.get("max_entity_id") == entity_ids[1] hass.states.async_set(entity_ids[2], STATE_UNKNOWN) await hass.async_block_till_done() state = hass.states.get("sensor.test_max") assert state.state not in [STATE_UNAVAILABLE, STATE_UNKNOWN] - assert entity_ids[1] == state.attributes.get("max_entity_id") + assert state.attributes.get("max_entity_id") == entity_ids[1] hass.states.async_set(entity_ids[1], STATE_UNAVAILABLE) await hass.async_block_till_done() state = hass.states.get("sensor.test_max") - assert state.state == STATE_UNAVAILABLE + assert state.state == STATE_UNKNOWN assert state.attributes.get("min_entity_id") is None assert state.attributes.get("max_entity_id") is None async def test_reload(hass: HomeAssistant) -> None: """Verify we can reload sensors.""" - hass.states.async_set("sensor.test_1", 12345) - hass.states.async_set("sensor.test_2", 45678) + hass.states.async_set("sensor.test_1", "12345") + hass.states.async_set("sensor.test_2", "45678") await async_setup_component( hass, @@ -249,8 +274,28 @@ async def test_reload(hass: HomeAssistant) -> None: assert hass.states.get("sensor.second_test") +@pytest.mark.parametrize( + ("states_list", "expected_group_state"), + [ + (STATES_ONE_ERROR, "17.0"), + (STATES_ONE_MISSING, "17.0"), + (STATES_ONE_UNKNOWN, "17.0"), + (STATES_ONE_UNAVAILABLE, "17.0"), + (STATES_ALL_ERROR, STATE_UNKNOWN), + (STATES_ALL_MISSING, STATE_UNAVAILABLE), + (STATES_ALL_UNKNOWN, STATE_UNKNOWN), + (STATES_ALL_UNAVAILABLE, STATE_UNAVAILABLE), + (STATES_MIX_MISSING_UNAVAILABLE, STATE_UNAVAILABLE), + (STATES_MIX_MISSING_UNKNOWN, STATE_UNKNOWN), + (STATES_MIX_UNAVAILABLE_UNKNOWN, STATE_UNKNOWN), + (STATES_MIX_MISSING_UNAVAILABLE_UNKNOWN, STATE_UNKNOWN), + ], +) async def test_sensor_incorrect_state_with_ignore_non_numeric( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + states_list: list[str | None], + expected_group_state: str, ) -> None: """Test that non numeric values are ignored in a group.""" config = { @@ -271,27 +316,48 @@ async def test_sensor_incorrect_state_with_ignore_non_numeric( entity_ids = config["sensor"]["entities"] # Check that the final sensor value ignores the non numeric input - for entity_id, value in dict(zip(entity_ids, VALUES_ERROR, strict=False)).items(): - hass.states.async_set(entity_id, value) + for entity_id, value in dict(zip(entity_ids, states_list, strict=False)).items(): + set_or_remove_state(hass, entity_id, value) await hass.async_block_till_done() state = hass.states.get("sensor.test_ignore_non_numeric") - assert state.state == "17.0" + assert state.state == expected_group_state assert ( "Unable to use state. Only numerical states are supported," not in caplog.text ) # Check that the final sensor value with all numeric inputs for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): - hass.states.async_set(entity_id, value) + hass.states.async_set(entity_id, str(value)) await hass.async_block_till_done() state = hass.states.get("sensor.test_ignore_non_numeric") assert state.state == "20.0" +@pytest.mark.parametrize( + ("states_list", "expected_group_state", "error_count"), + [ + (STATES_ONE_ERROR, STATE_UNKNOWN, 1), + (STATES_ONE_MISSING, STATE_UNKNOWN, 0), + (STATES_ONE_UNKNOWN, STATE_UNKNOWN, 1), + (STATES_ONE_UNAVAILABLE, STATE_UNKNOWN, 1), + (STATES_ALL_ERROR, STATE_UNKNOWN, 3), + (STATES_ALL_MISSING, STATE_UNAVAILABLE, 0), + (STATES_ALL_UNKNOWN, STATE_UNKNOWN, 3), + (STATES_ALL_UNAVAILABLE, STATE_UNAVAILABLE, 3), + (STATES_MIX_MISSING_UNAVAILABLE, STATE_UNAVAILABLE, 2), + (STATES_MIX_MISSING_UNKNOWN, STATE_UNKNOWN, 2), + (STATES_MIX_UNAVAILABLE_UNKNOWN, STATE_UNKNOWN, 3), + (STATES_MIX_MISSING_UNAVAILABLE_UNKNOWN, STATE_UNKNOWN, 2), + ], +) async def test_sensor_incorrect_state_with_not_ignore_non_numeric( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + states_list: list[str | None], + expected_group_state: str, + error_count: int, ) -> None: """Test that non numeric values cause a group to be unknown.""" config = { @@ -312,24 +378,46 @@ async def test_sensor_incorrect_state_with_not_ignore_non_numeric( entity_ids = config["sensor"]["entities"] # Check that the final sensor value is unavailable if a non numeric input exists - for entity_id, value in dict(zip(entity_ids, VALUES_ERROR, strict=False)).items(): - hass.states.async_set(entity_id, value) + for entity_id, value in dict(zip(entity_ids, states_list, strict=False)).items(): + set_or_remove_state(hass, entity_id, value) await hass.async_block_till_done() state = hass.states.get("sensor.test_failure") - assert state.state == "unknown" - assert "Unable to use state. Only numerical states are supported" in caplog.text + assert state.state == expected_group_state + assert ( + caplog.text.count("Unable to use state. Only numerical states are supported") + == error_count + ) # Check that the final sensor value is correct with all numeric inputs for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): - hass.states.async_set(entity_id, value) + hass.states.async_set(entity_id, str(value)) await hass.async_block_till_done() state = hass.states.get("sensor.test_failure") assert state.state == "20.0" -async def test_sensor_require_all_states(hass: HomeAssistant) -> None: +@pytest.mark.parametrize( + ("states_list", "expected_group_state"), + [ + (STATES_ONE_ERROR, STATE_UNKNOWN), + (STATES_ONE_MISSING, STATE_UNKNOWN), + (STATES_ONE_UNKNOWN, STATE_UNKNOWN), + (STATES_ONE_UNAVAILABLE, STATE_UNKNOWN), + (STATES_ALL_ERROR, STATE_UNKNOWN), + (STATES_ALL_MISSING, STATE_UNAVAILABLE), + (STATES_ALL_UNKNOWN, STATE_UNKNOWN), + (STATES_ALL_UNAVAILABLE, STATE_UNAVAILABLE), + (STATES_MIX_MISSING_UNAVAILABLE, STATE_UNAVAILABLE), + (STATES_MIX_MISSING_UNKNOWN, STATE_UNKNOWN), + (STATES_MIX_UNAVAILABLE_UNKNOWN, STATE_UNKNOWN), + (STATES_MIX_MISSING_UNAVAILABLE_UNKNOWN, STATE_UNKNOWN), + ], +) +async def test_sensor_require_all_states( + hass: HomeAssistant, states_list: list[str | None], expected_group_state: str +) -> None: """Test the sum sensor with missing state require all.""" config = { SENSOR_DOMAIN: { @@ -348,13 +436,13 @@ async def test_sensor_require_all_states(hass: HomeAssistant) -> None: entity_ids = config["sensor"]["entities"] - for entity_id, value in dict(zip(entity_ids, VALUES_ERROR, strict=False)).items(): - hass.states.async_set(entity_id, value) + for entity_id, value in dict(zip(entity_ids, states_list, strict=False)).items(): + set_or_remove_state(hass, entity_id, value) await hass.async_block_till_done() state = hass.states.get("sensor.test_sum") - assert state.state == STATE_UNKNOWN + assert state.state == expected_group_state async def test_sensor_calculated_properties(hass: HomeAssistant) -> None: @@ -373,7 +461,7 @@ async def test_sensor_calculated_properties(hass: HomeAssistant) -> None: hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -382,7 +470,7 @@ async def test_sensor_calculated_properties(hass: HomeAssistant) -> None: ) hass.states.async_set( entity_ids[1], - VALUES[1], + str(VALUES[1]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -391,7 +479,7 @@ async def test_sensor_calculated_properties(hass: HomeAssistant) -> None: ) hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -413,7 +501,7 @@ async def test_sensor_calculated_properties(hass: HomeAssistant) -> None: # is converted correctly by the group sensor hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -446,7 +534,7 @@ async def test_sensor_with_uoms_but_no_device_class( hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.POWER, "state_class": SensorStateClass.MEASUREMENT, @@ -455,7 +543,7 @@ async def test_sensor_with_uoms_but_no_device_class( ) hass.states.async_set( entity_ids[1], - VALUES[1], + str(VALUES[1]), { "device_class": SensorDeviceClass.POWER, "state_class": SensorStateClass.MEASUREMENT, @@ -464,7 +552,7 @@ async def test_sensor_with_uoms_but_no_device_class( ) hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "unit_of_measurement": "W", }, @@ -487,7 +575,7 @@ async def test_sensor_with_uoms_but_no_device_class( hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.POWER, "state_class": SensorStateClass.MEASUREMENT, @@ -508,7 +596,7 @@ async def test_sensor_with_uoms_but_no_device_class( hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.POWER, "state_class": SensorStateClass.MEASUREMENT, @@ -541,7 +629,7 @@ async def test_sensor_calculated_properties_not_same( hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -550,7 +638,7 @@ async def test_sensor_calculated_properties_not_same( ) hass.states.async_set( entity_ids[1], - VALUES[1], + str(VALUES[1]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -559,7 +647,7 @@ async def test_sensor_calculated_properties_not_same( ) hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "device_class": SensorDeviceClass.CURRENT, "state_class": SensorStateClass.MEASUREMENT, @@ -604,7 +692,7 @@ async def test_sensor_calculated_result_fails_on_uom(hass: HomeAssistant) -> Non hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -613,7 +701,7 @@ async def test_sensor_calculated_result_fails_on_uom(hass: HomeAssistant) -> Non ) hass.states.async_set( entity_ids[1], - VALUES[1], + str(VALUES[1]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -622,7 +710,7 @@ async def test_sensor_calculated_result_fails_on_uom(hass: HomeAssistant) -> Non ) hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -642,7 +730,7 @@ async def test_sensor_calculated_result_fails_on_uom(hass: HomeAssistant) -> Non hass.states.async_set( entity_ids[2], - 12, + "12", { "device_class": SensorDeviceClass.ENERGY, "state_class": SensorStateClass.TOTAL, @@ -652,7 +740,7 @@ async def test_sensor_calculated_result_fails_on_uom(hass: HomeAssistant) -> Non await hass.async_block_till_done() state = hass.states.get("sensor.test_sum") - assert state.state == STATE_UNAVAILABLE + assert state.state == STATE_UNKNOWN assert state.attributes.get("device_class") == "energy" assert state.attributes.get("state_class") == "total" assert state.attributes.get("unit_of_measurement") is None @@ -677,7 +765,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class( hass.states.async_set( entity_ids[0], - VALUES[0], + str(VALUES[0]), { "device_class": SensorDeviceClass.HUMIDITY, "state_class": SensorStateClass.MEASUREMENT, @@ -686,7 +774,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class( ) hass.states.async_set( entity_ids[1], - VALUES[1], + str(VALUES[1]), { "device_class": SensorDeviceClass.HUMIDITY, "state_class": SensorStateClass.MEASUREMENT, @@ -695,7 +783,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class( ) hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "device_class": SensorDeviceClass.HUMIDITY, "state_class": SensorStateClass.MEASUREMENT, @@ -720,7 +808,7 @@ async def test_sensor_calculated_properties_not_convertible_device_class( hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "device_class": SensorDeviceClass.HUMIDITY, "state_class": SensorStateClass.MEASUREMENT, @@ -759,12 +847,18 @@ async def test_last_sensor(hass: HomeAssistant) -> None: entity_ids = config["sensor"]["entities"] - for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): - hass.states.async_set(entity_id, value) + for entity_id in entity_ids[1:]: + hass.states.async_set(entity_id, "0.0") await hass.async_block_till_done() state = hass.states.get("sensor.test_last") - assert str(float(value)) == state.state - assert entity_id == state.attributes.get("last_entity_id") + assert state.state == STATE_UNKNOWN + + for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): + hass.states.async_set(entity_id, str(value)) + await hass.async_block_till_done() + state = hass.states.get("sensor.test_last") + assert state.state == str(float(value)) + assert state.attributes.get("last_entity_id") == entity_id async def test_sensors_attributes_added_when_entity_info_available( @@ -797,7 +891,7 @@ async def test_sensors_attributes_added_when_entity_info_available( for entity_id, value in dict(zip(entity_ids, VALUES, strict=False)).items(): hass.states.async_set( entity_id, - value, + str(value), { ATTR_DEVICE_CLASS: SensorDeviceClass.VOLUME, ATTR_STATE_CLASS: SensorStateClass.TOTAL, @@ -843,9 +937,9 @@ async def test_sensor_state_class_no_uom_not_available( "unit_of_measurement": PERCENTAGE, } - hass.states.async_set(entity_ids[0], VALUES[0], input_attributes) - hass.states.async_set(entity_ids[1], VALUES[1], input_attributes) - hass.states.async_set(entity_ids[2], VALUES[2], input_attributes) + hass.states.async_set(entity_ids[0], str(VALUES[0]), input_attributes) + hass.states.async_set(entity_ids[1], str(VALUES[1]), input_attributes) + hass.states.async_set(entity_ids[2], str(VALUES[2]), input_attributes) await hass.async_block_till_done() assert await async_setup_component(hass, "sensor", config) @@ -864,7 +958,7 @@ async def test_sensor_state_class_no_uom_not_available( # sensor.test_3 drops the unit of measurement hass.states.async_set( entity_ids[2], - VALUES[2], + str(VALUES[2]), { "state_class": SensorStateClass.MEASUREMENT, }, @@ -914,7 +1008,7 @@ async def test_sensor_different_attributes_ignore_non_numeric( test_cases = [ { "entity": entity_ids[0], - "value": VALUES[0], + "value": str(VALUES[0]), "attributes": { "state_class": SensorStateClass.MEASUREMENT, "unit_of_measurement": PERCENTAGE, @@ -926,7 +1020,7 @@ async def test_sensor_different_attributes_ignore_non_numeric( }, { "entity": entity_ids[1], - "value": VALUES[1], + "value": str(VALUES[1]), "attributes": { "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.HUMIDITY, @@ -939,7 +1033,7 @@ async def test_sensor_different_attributes_ignore_non_numeric( }, { "entity": entity_ids[2], - "value": VALUES[2], + "value": str(VALUES[2]), "attributes": { "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.TEMPERATURE, @@ -952,7 +1046,7 @@ async def test_sensor_different_attributes_ignore_non_numeric( }, { "entity": entity_ids[2], - "value": VALUES[2], + "value": str(VALUES[2]), "attributes": { "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.HUMIDITY, @@ -966,7 +1060,7 @@ async def test_sensor_different_attributes_ignore_non_numeric( }, { "entity": entity_ids[0], - "value": VALUES[0], + "value": str(VALUES[0]), "attributes": { "state_class": SensorStateClass.MEASUREMENT, "device_class": SensorDeviceClass.HUMIDITY, @@ -980,7 +1074,7 @@ async def test_sensor_different_attributes_ignore_non_numeric( }, { "entity": entity_ids[0], - "value": VALUES[0], + "value": str(VALUES[0]), "attributes": { "state_class": SensorStateClass.MEASUREMENT, }, diff --git a/tests/components/growatt_server/snapshots/test_number.ambr b/tests/components/growatt_server/snapshots/test_number.ambr index 03e3cb87861..e43cf4fea40 100644 --- a/tests/components/growatt_server/snapshots/test_number.ambr +++ b/tests/components/growatt_server/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charge power limit', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charge SOC limit', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharge power limit', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharge SOC limit', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/growatt_server/snapshots/test_sensor.ambr b/tests/components/growatt_server/snapshots/test_sensor.ambr index f5f177e24ce..a6c2365fa08 100644 --- a/tests/components/growatt_server/snapshots/test_sensor.ambr +++ b/tests/components/growatt_server/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All batteries charged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -133,6 +135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All batteries discharged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Batteries charged from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -247,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 1 charging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -304,6 +309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 1 discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -361,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 2 charging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -418,6 +425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 2 discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -475,6 +483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -532,6 +541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -589,6 +599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -646,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -703,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -760,6 +773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -817,6 +831,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export to grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -874,6 +889,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -931,6 +947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -986,6 +1003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1040,6 +1058,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1096,6 +1115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1151,6 +1171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1205,6 +1226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1261,6 +1283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1316,6 +1339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1370,6 +1394,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1426,6 +1451,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1481,6 +1507,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1535,6 +1562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1591,6 +1619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1648,6 +1677,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1705,6 +1735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime batteries charged from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1762,6 +1793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1819,6 +1851,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime import from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1876,6 +1909,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime self consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1933,6 +1967,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime system production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1990,6 +2025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total all batteries charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2047,6 +2083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total all batteries discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2104,6 +2141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 1 charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2161,6 +2199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 1 discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2218,6 +2257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 2 charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2275,6 +2315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 2 discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2332,6 +2373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2389,6 +2431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2446,6 +2489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2503,6 +2547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2560,6 +2605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total export to grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2617,6 +2663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2674,6 +2721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total solar energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2731,6 +2779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2788,6 +2837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local load power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2845,6 +2895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2900,6 +2951,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2956,6 +3008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3013,6 +3066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3070,6 +3124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3125,6 +3180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge (SoC)', 'options': dict({ }), 'original_device_class': , @@ -3178,6 +3234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3235,6 +3292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3290,6 +3348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3344,6 +3403,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3398,6 +3458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3452,6 +3513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3506,6 +3568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3562,6 +3625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3619,6 +3683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3676,6 +3741,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3731,6 +3797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Money lifetime', 'options': dict({ }), 'original_device_class': None, @@ -3782,6 +3849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3837,6 +3905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total money today', 'options': dict({ }), 'original_device_class': None, @@ -3888,6 +3957,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3945,6 +4015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4002,6 +4073,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4059,6 +4131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4116,6 +4189,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4173,6 +4247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4230,6 +4305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4287,6 +4363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4344,6 +4421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4401,6 +4479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4458,6 +4537,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4515,6 +4595,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intelligent Power Management temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4572,6 +4653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4629,6 +4711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4686,6 +4769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4743,6 +4827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4800,6 +4885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4857,6 +4943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4914,6 +5001,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4971,6 +5059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5028,6 +5117,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5085,6 +5175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5140,6 +5231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Money lifetime', 'options': dict({ }), 'original_device_class': None, @@ -5192,6 +5284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5247,6 +5340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total money today', 'options': dict({ }), 'original_device_class': None, @@ -5299,6 +5393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All PV wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5356,6 +5451,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5413,6 +5509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charging', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5470,6 +5567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5527,6 +5625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharging kW', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5584,6 +5683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5639,6 +5739,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5695,6 +5796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export to grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5752,6 +5854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export to grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5807,6 +5910,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5863,6 +5967,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5920,6 +6025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid today (load)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5977,6 +6083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid today (load + charging)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6032,6 +6139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last data update', 'options': dict({ }), 'original_device_class': , @@ -6084,6 +6192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6141,6 +6250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6198,6 +6308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime export to grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6255,6 +6366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6312,6 +6424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime solar energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6369,6 +6482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6426,6 +6540,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6483,6 +6598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today (battery)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6540,6 +6656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today (solar)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6595,6 +6712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV1 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6651,6 +6769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV1 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6706,6 +6825,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV2 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6762,6 +6882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV2 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6819,6 +6940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-consumption today (solar + battery)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6876,6 +6998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6931,6 +7054,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge', 'options': dict({ }), 'original_device_class': , @@ -6984,6 +7108,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System production today (self-consumption + export)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7041,6 +7166,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7098,6 +7224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7155,6 +7282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7210,6 +7338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Money lifetime', 'options': dict({ }), 'original_device_class': None, @@ -7262,6 +7391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7317,6 +7447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total money today', 'options': dict({ }), 'original_device_class': None, @@ -7369,6 +7500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC input frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7426,6 +7558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC input voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7483,6 +7616,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC output frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7540,6 +7674,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery percentage', 'options': dict({ }), 'original_device_class': , @@ -7594,6 +7729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7651,6 +7787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7708,6 +7845,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid charge current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7765,6 +7903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid charged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7822,6 +7961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid discharged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7879,6 +8019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid out current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7936,6 +8077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7993,6 +8135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8050,6 +8193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8107,6 +8251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime grid charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8164,6 +8309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime grid discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8221,6 +8367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8278,6 +8425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime solar output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8335,6 +8483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime storage production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8392,6 +8541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime stored charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8449,6 +8599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8506,6 +8657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption (solar + storage)', 'options': dict({ }), 'original_device_class': None, @@ -8559,6 +8711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8616,6 +8769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load percentage', 'options': dict({ }), 'original_device_class': , @@ -8670,6 +8824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8727,6 +8882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV1 charging voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8784,6 +8940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV1 current to storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8841,6 +8998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV2 charging voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8898,6 +9056,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV2 current to storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8955,6 +9114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar charge current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9012,6 +9172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar output today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9069,6 +9230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar power production (PV1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9126,6 +9288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar power production (PV2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9183,6 +9346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage charging/ discharging(-ve)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9240,6 +9404,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9297,6 +9462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9354,6 +9520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9411,6 +9578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9466,6 +9634,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Money lifetime', 'options': dict({ }), 'original_device_class': None, @@ -9518,6 +9687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9573,6 +9743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total money today', 'options': dict({ }), 'original_device_class': None, @@ -9625,6 +9796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9682,6 +9854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9739,6 +9912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9794,6 +9968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Money lifetime', 'options': dict({ }), 'original_device_class': None, @@ -9846,6 +10021,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9901,6 +10077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total money today', 'options': dict({ }), 'original_device_class': None, @@ -9951,6 +10128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10007,6 +10185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All batteries charged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10064,6 +10243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All batteries discharged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10121,6 +10301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Batteries charged from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10178,6 +10359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 1 charging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10235,6 +10417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 1 discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10292,6 +10475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 2 charging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10349,6 +10533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 2 discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10406,6 +10591,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10463,6 +10649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10520,6 +10707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10577,6 +10765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10634,6 +10823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10691,6 +10881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10748,6 +10939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export to grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10805,6 +10997,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10862,6 +11055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10917,6 +11111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10971,6 +11166,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11027,6 +11223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11082,6 +11279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11136,6 +11334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11192,6 +11391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11247,6 +11447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11301,6 +11502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11357,6 +11559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11412,6 +11615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11466,6 +11670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11522,6 +11727,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11579,6 +11785,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11636,6 +11843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime batteries charged from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11693,6 +11901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11750,6 +11959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime import from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11807,6 +12017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime self consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11864,6 +12075,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime system production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11921,6 +12133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total all batteries charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11978,6 +12191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total all batteries discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12035,6 +12249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 1 charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12092,6 +12307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 1 discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12149,6 +12365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 2 charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12206,6 +12423,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 2 discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12263,6 +12481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12320,6 +12539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12377,6 +12597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12434,6 +12655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12491,6 +12713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total export to grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12548,6 +12771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12605,6 +12829,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total solar energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12662,6 +12887,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12719,6 +12945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local load power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12776,6 +13003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12831,6 +13059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12887,6 +13116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12944,6 +13174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13001,6 +13232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13056,6 +13288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge (SoC)', 'options': dict({ }), 'original_device_class': , @@ -13109,6 +13342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13166,6 +13400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13221,6 +13456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13275,6 +13511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13329,6 +13566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13383,6 +13621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13437,6 +13676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13493,6 +13733,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13550,6 +13791,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13607,6 +13849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13662,6 +13905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Money lifetime', 'options': dict({ }), 'original_device_class': None, @@ -13714,6 +13958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13769,6 +14014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total money today', 'options': dict({ }), 'original_device_class': None, @@ -13819,6 +14065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13875,6 +14122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All batteries charged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13932,6 +14180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All batteries discharged today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13989,6 +14238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Batteries charged from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14046,6 +14296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 1 charging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14103,6 +14354,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 1 discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14160,6 +14412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 2 charging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14217,6 +14470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery 2 discharging W', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14274,6 +14528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14331,6 +14586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14388,6 +14644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14445,6 +14702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14502,6 +14760,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14559,6 +14818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14616,6 +14876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Export to grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14673,6 +14934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import from grid today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14730,6 +14992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Import power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14785,6 +15048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14839,6 +15103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14895,6 +15160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14950,6 +15216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15004,6 +15271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15060,6 +15328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15115,6 +15384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15169,6 +15439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15225,6 +15496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15280,6 +15552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 amperage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15334,6 +15607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15390,6 +15664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4 wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15447,6 +15722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal wattage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15504,6 +15780,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime batteries charged from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15561,6 +15838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15618,6 +15896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime import from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15675,6 +15954,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime self consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15732,6 +16012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime system production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15789,6 +16070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total all batteries charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15846,6 +16128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total all batteries discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15903,6 +16186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 1 charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15960,6 +16244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 1 discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16017,6 +16302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 2 charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16074,6 +16360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total battery 2 discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16131,6 +16418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16188,6 +16476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16245,6 +16534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16302,6 +16592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total energy input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16359,6 +16650,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total export to grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16416,6 +16708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total load consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16473,6 +16766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime total solar energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16530,6 +16824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16587,6 +16882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local load power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16644,6 +16940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16699,6 +16996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16755,6 +17053,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16812,6 +17111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16869,6 +17169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16924,6 +17225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge (SoC)', 'options': dict({ }), 'original_device_class': , @@ -16977,6 +17279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17034,6 +17337,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System production today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17089,6 +17393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17143,6 +17448,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17197,6 +17503,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17251,6 +17558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17305,6 +17613,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature 5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/growatt_server/snapshots/test_switch.ambr b/tests/components/growatt_server/snapshots/test_switch.ambr index d3d7d981bbb..e42dda3a8f0 100644 --- a/tests/components/growatt_server/snapshots/test_switch.ambr +++ b/tests/components/growatt_server/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge from grid', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/habitica/snapshots/test_binary_sensor.ambr b/tests/components/habitica/snapshots/test_binary_sensor.ambr index 4a06b92035e..c117f89036c 100644 --- a/tests/components/habitica/snapshots/test_binary_sensor.ambr +++ b/tests/components/habitica/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pending quest invitation', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quest status', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/habitica/snapshots/test_button.ambr b/tests/components/habitica/snapshots/test_button.ambr index 9d7e2411590..b8cb4c28f35 100644 --- a/tests/components/habitica/snapshots/test_button.ambr +++ b/tests/components/habitica/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allocate all stat points', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Blessing', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buy a health potion', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Healing light', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Protective aura', 'options': dict({ }), 'original_device_class': None, @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Revive from death', 'options': dict({ }), 'original_device_class': None, @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Searing brightness', 'options': dict({ }), 'original_device_class': None, @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start my day', 'options': dict({ }), 'original_device_class': None, @@ -409,6 +417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allocate all stat points', 'options': dict({ }), 'original_device_class': None, @@ -457,6 +466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buy a health potion', 'options': dict({ }), 'original_device_class': None, @@ -506,6 +516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Revive from death', 'options': dict({ }), 'original_device_class': None, @@ -554,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start my day', 'options': dict({ }), 'original_device_class': None, @@ -602,6 +614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stealth', 'options': dict({ }), 'original_device_class': None, @@ -651,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tools of the trade', 'options': dict({ }), 'original_device_class': None, @@ -700,6 +714,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allocate all stat points', 'options': dict({ }), 'original_device_class': None, @@ -748,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buy a health potion', 'options': dict({ }), 'original_device_class': None, @@ -797,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defensive stance', 'options': dict({ }), 'original_device_class': None, @@ -846,6 +863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intimidating gaze', 'options': dict({ }), 'original_device_class': None, @@ -895,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Revive from death', 'options': dict({ }), 'original_device_class': None, @@ -943,6 +962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start my day', 'options': dict({ }), 'original_device_class': None, @@ -991,6 +1011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valorous presence', 'options': dict({ }), 'original_device_class': None, @@ -1040,6 +1061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allocate all stat points', 'options': dict({ }), 'original_device_class': None, @@ -1088,6 +1110,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buy a health potion', 'options': dict({ }), 'original_device_class': None, @@ -1137,6 +1160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chilling frost', 'options': dict({ }), 'original_device_class': None, @@ -1186,6 +1210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Earthquake', 'options': dict({ }), 'original_device_class': None, @@ -1235,6 +1260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ethereal surge', 'options': dict({ }), 'original_device_class': None, @@ -1284,6 +1310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Revive from death', 'options': dict({ }), 'original_device_class': None, @@ -1332,6 +1359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start my day', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/habitica/snapshots/test_calendar.ambr b/tests/components/habitica/snapshots/test_calendar.ambr index a59b984c63e..5b3ee652a5a 100644 --- a/tests/components/habitica/snapshots/test_calendar.ambr +++ b/tests/components/habitica/snapshots/test_calendar.ambr @@ -948,6 +948,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dailies', 'options': dict({ }), 'original_device_class': None, @@ -1003,6 +1004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily reminders', 'options': dict({ }), 'original_device_class': None, @@ -1057,6 +1059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'To-do reminders', 'options': dict({ }), 'original_device_class': None, @@ -1111,6 +1114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "To-Do's", 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/habitica/snapshots/test_notify.ambr b/tests/components/habitica/snapshots/test_notify.ambr index 248f6e292d6..53b23a8fbc0 100644 --- a/tests/components/habitica/snapshots/test_notify.ambr +++ b/tests/components/habitica/snapshots/test_notify.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Party chat', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Private message: test-partymember-displayname', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/habitica/snapshots/test_sensor.ambr b/tests/components/habitica/snapshots/test_sensor.ambr index 5b01a2f4f30..01e74ac5829 100644 --- a/tests/components/habitica/snapshots/test_sensor.ambr +++ b/tests/components/habitica/snapshots/test_sensor.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Class', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Constitution', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display name', 'options': dict({ }), 'original_device_class': None, @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Experience', 'options': dict({ }), 'original_device_class': None, @@ -243,6 +247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -296,6 +301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intelligence', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -353,6 +359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last check-in', 'options': dict({ }), 'original_device_class': , @@ -402,6 +409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level', 'options': dict({ }), 'original_device_class': None, @@ -450,6 +458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mana', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -503,6 +512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max. mana', 'options': dict({ }), 'original_device_class': None, @@ -553,6 +563,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next level', 'options': dict({ }), 'original_device_class': None, @@ -603,6 +614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Perception', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -660,6 +672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -724,6 +737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Class', 'options': dict({ }), 'original_device_class': , @@ -780,6 +794,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Constitution', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -837,6 +852,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display name', 'options': dict({ }), 'original_device_class': None, @@ -891,6 +907,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Eggs', 'options': dict({ }), 'original_device_class': None, @@ -944,6 +961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Experience', 'options': dict({ }), 'original_device_class': None, @@ -994,6 +1012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gems', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1047,6 +1066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gold', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1100,6 +1120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hatching potions', 'options': dict({ }), 'original_device_class': None, @@ -1153,6 +1174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1206,6 +1228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intelligence', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1263,6 +1286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last check-in', 'options': dict({ }), 'original_device_class': , @@ -1312,6 +1336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level', 'options': dict({ }), 'original_device_class': None, @@ -1360,6 +1385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mana', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1413,6 +1439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max. mana', 'options': dict({ }), 'original_device_class': None, @@ -1463,6 +1490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mystic hourglasses', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1516,6 +1544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next level', 'options': dict({ }), 'original_device_class': None, @@ -1566,6 +1595,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pending damage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1619,6 +1649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pending quest items', 'options': dict({ }), 'original_device_class': None, @@ -1668,6 +1699,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Perception', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1725,6 +1757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pet food', 'options': dict({ }), 'original_device_class': None, @@ -1778,6 +1811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quest scrolls', 'options': dict({ }), 'original_device_class': None, @@ -1832,6 +1866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boss health', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1885,6 +1920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boss health remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1938,6 +1974,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boss rage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1991,6 +2028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boss rage limit break', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2046,6 +2084,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Collected quest items', 'options': dict({ }), 'original_device_class': None, @@ -2097,6 +2136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Group leader', 'options': dict({ }), 'original_device_class': None, @@ -2145,6 +2185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Member count', 'options': dict({ }), 'original_device_class': None, @@ -2195,6 +2236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quest', 'options': dict({ }), 'original_device_class': None, @@ -2246,6 +2288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quest boss', 'options': dict({ }), 'original_device_class': None, @@ -2294,6 +2337,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Saddles', 'options': dict({ }), 'original_device_class': None, @@ -2344,6 +2388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/habitica/snapshots/test_switch.ambr b/tests/components/habitica/snapshots/test_switch.ambr index 7794f8f5e8d..0f7cdd669df 100644 --- a/tests/components/habitica/snapshots/test_switch.ambr +++ b/tests/components/habitica/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rest in the inn', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/habitica/snapshots/test_todo.ambr b/tests/components/habitica/snapshots/test_todo.ambr index 52f901322a3..47d26892c77 100644 --- a/tests/components/habitica/snapshots/test_todo.ambr +++ b/tests/components/habitica/snapshots/test_todo.ambr @@ -134,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dailies', 'options': dict({ }), 'original_device_class': None, @@ -183,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "To-Do's", 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/hassio/test_addon_panel.py b/tests/components/hassio/test_addon_panel.py index 2c3552c8d08..e2a7b53d04e 100644 --- a/tests/components/hassio/test_addon_panel.py +++ b/tests/components/hassio/test_addon_panel.py @@ -130,3 +130,44 @@ async def test_hassio_addon_panel_api( "test1", {"enable": True, "title": "Test", "icon": "mdi:test", "admin": False}, ) + + +@pytest.mark.usefixtures("hassio_env") +async def test_hassio_addon_panel_registration( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test panel registration calls frontend.async_register_built_in_panel.""" + aioclient_mock.get( + "http://127.0.0.1/ingress/panels", + json={ + "result": "ok", + "data": { + "panels": { + "test_addon": { + "enable": True, + "title": "Test Addon", + "icon": "mdi:test-tube", + "admin": True, + }, + } + }, + }, + ) + + with patch( + "homeassistant.components.hassio.addon_panel.frontend.async_register_built_in_panel" + ) as mock_register: + await async_setup_component(hass, "hassio", {}) + await hass.async_block_till_done() + + # Verify that async_register_built_in_panel was called with correct arguments + # for our test addon + mock_register.assert_any_call( + hass, + "app", + frontend_url_path="test_addon", + sidebar_title="Test Addon", + sidebar_icon="mdi:test-tube", + require_admin=True, + config={"addon": "test_addon"}, + ) diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index 8008d5ae5f4..44011c153d8 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -260,6 +260,27 @@ async def test_setup_api_panel( } +async def test_setup_app_panel(hass: HomeAssistant) -> None: + """Test app panel is registered.""" + with patch.dict(os.environ, MOCK_ENVIRON): + result = await async_setup_component(hass, "hassio", {}) + await hass.async_block_till_done() + assert result + + panels = hass.data[frontend.DATA_PANELS] + + assert panels.get("app").to_response() == { + "component_name": "app", + "icon": None, + "title": None, + "default_visible": True, + "config": None, + "url_path": "app", + "require_admin": False, + "config_panel_domain": None, + } + + async def test_setup_api_push_api_data( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, diff --git a/tests/components/hdfury/conftest.py b/tests/components/hdfury/conftest.py index 7f7b760856d..5943a56ab80 100644 --- a/tests/components/hdfury/conftest.py +++ b/tests/components/hdfury/conftest.py @@ -68,6 +68,20 @@ def mock_hdfury_client() -> Generator[AsyncMock]: "portseltx0": "0", "portseltx1": "4", "opmode": "0", + "RX0": "4K59.937 593MHz 422 BT2020 12b 2.2", + "RX1": "no signal", + "TX0": "4K59.937 593MHz 422 BT2020 12b 2.2", + "TX1": "4K59.937 593MHz 422 BT2020 12b 2.2", + "AUD0": "bitstream 48kHz", + "AUD1": "bitstream 48kHz", + "AUDOUT": "bitstream 48kHz", + "EARCRX": "eARC/ARC not active", + "SINK0": "LG TV SSCR2: 4K120 444 FRL6 VRR DSC ALLM DV HDR10 HLG", + "EDIDA0": "MAT Atmos, DD Atmos, DD, DTS:X+IMAX, DTSHD, DTS, LPCM 2.0 192kHz 24b", + "SINK1": "Signify FCD: 4K60 444 DV HDR10+ HLG", + "EDIDA1": "DD, DTS, LPCM 2.0 48kHz 24b", + "SINK2": "Bose CineMate: 4K60 420 ", + "EDIDA2": "DD, DTS, LPCM 7.1 96kHz 24b", } ) coord_client.get_config = AsyncMock( diff --git a/tests/components/hdfury/snapshots/test_button.ambr b/tests/components/hdfury/snapshots/test_button.ambr index 9cf96a0e164..4459bab471f 100644 --- a/tests/components/hdfury/snapshots/test_button.ambr +++ b/tests/components/hdfury/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Issue hotplug', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/hdfury/snapshots/test_diagnostics.ambr b/tests/components/hdfury/snapshots/test_diagnostics.ambr new file mode 100644 index 00000000000..414fbdcc229 --- /dev/null +++ b/tests/components/hdfury/snapshots/test_diagnostics.ambr @@ -0,0 +1,44 @@ +# serializer version: 1 +# name: test_diagnostics + dict({ + 'board': dict({ + 'hostname': 'VRROOM-02', + 'ipaddress': '192.168.1.123', + 'pcbv': '3', + 'serial': '000123456789', + 'version': 'FW: 0.61', + }), + 'config': dict({ + 'autosw': '1', + 'htpcmode0': '0', + 'htpcmode1': '0', + 'htpcmode2': '0', + 'htpcmode3': '0', + 'iractive': '1', + 'macaddr': 'c7:1c:df:9d:f6:40', + 'mutetx0': '1', + 'mutetx1': '1', + 'oled': '1', + 'relay': '0', + }), + 'info': dict({ + 'AUD0': 'bitstream 48kHz', + 'AUD1': 'bitstream 48kHz', + 'AUDOUT': 'bitstream 48kHz', + 'EARCRX': 'eARC/ARC not active', + 'EDIDA0': 'MAT Atmos, DD Atmos, DD, DTS:X+IMAX, DTSHD, DTS, LPCM 2.0 192kHz 24b', + 'EDIDA1': 'DD, DTS, LPCM 2.0 48kHz 24b', + 'EDIDA2': 'DD, DTS, LPCM 7.1 96kHz 24b', + 'RX0': '4K59.937 593MHz 422 BT2020 12b 2.2', + 'RX1': 'no signal', + 'SINK0': 'LG TV SSCR2: 4K120 444 FRL6 VRR DSC ALLM DV HDR10 HLG', + 'SINK1': 'Signify FCD: 4K60 444 DV HDR10+ HLG', + 'SINK2': 'Bose CineMate: 4K60 420 ', + 'TX0': '4K59.937 593MHz 422 BT2020 12b 2.2', + 'TX1': '4K59.937 593MHz 422 BT2020 12b 2.2', + 'opmode': '0', + 'portseltx0': '0', + 'portseltx1': '4', + }), + }) +# --- diff --git a/tests/components/hdfury/snapshots/test_select.ambr b/tests/components/hdfury/snapshots/test_select.ambr index 581cc895a0d..56cec253305 100644 --- a/tests/components/hdfury/snapshots/test_select.ambr +++ b/tests/components/hdfury/snapshots/test_select.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operation mode', 'options': dict({ }), 'original_device_class': None, @@ -93,6 +94,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port select TX0', 'options': dict({ }), 'original_device_class': None, @@ -156,6 +158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port select TX1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/hdfury/snapshots/test_sensor.ambr b/tests/components/hdfury/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..596135d3fff --- /dev/null +++ b/tests/components/hdfury/snapshots/test_sensor.ambr @@ -0,0 +1,687 @@ +# serializer version: 1 +# name: test_sensor_entities[sensor.hdfury_vrroom_02_audio_output-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_audio_output', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Audio output', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Audio output', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'audout', + 'unique_id': '000123456789_AUDOUT', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_audio_output-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Audio output', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_audio_output', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'bitstream 48kHz', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_audio_tx0-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_audio_tx0', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Audio TX0', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Audio TX0', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'aud0', + 'unique_id': '000123456789_AUD0', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_audio_tx0-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Audio TX0', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_audio_tx0', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'bitstream 48kHz', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_audio_tx1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_audio_tx1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Audio TX1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Audio TX1', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'aud1', + 'unique_id': '000123456789_AUD1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_audio_tx1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Audio TX1', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_audio_tx1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'bitstream 48kHz', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_earc_arc_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_earc_arc_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'eARC/ARC status', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'eARC/ARC status', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'earcrx', + 'unique_id': '000123456789_EARCRX', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_earc_arc_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 eARC/ARC status', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_earc_arc_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'eARC/ARC not active', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_aud-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_aud', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'EDID AUD', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'EDID AUD', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'sink2', + 'unique_id': '000123456789_SINK2', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_aud-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 EDID AUD', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_aud', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Bose CineMate: 4K60 420 ', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_auda-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_auda', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'EDID AUDA', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'EDID AUDA', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'edida2', + 'unique_id': '000123456789_EDIDA2', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_auda-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 EDID AUDA', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_auda', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'DD, DTS, LPCM 7.1 96kHz 24b', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_tx0-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_tx0', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'EDID TX0', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'EDID TX0', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'sink0', + 'unique_id': '000123456789_SINK0', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_tx0-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 EDID TX0', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_tx0', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'LG TV SSCR2: 4K120 444 FRL6 VRR DSC ALLM DV HDR10 HLG', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_tx1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_tx1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'EDID TX1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'EDID TX1', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'sink1', + 'unique_id': '000123456789_SINK1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_tx1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 EDID TX1', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_tx1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Signify FCD: 4K60 444 DV HDR10+ HLG', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_txa0-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_txa0', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'EDID TXA0', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'EDID TXA0', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'edida0', + 'unique_id': '000123456789_EDIDA0', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_txa0-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 EDID TXA0', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_txa0', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'MAT Atmos, DD Atmos, DD, DTS:X+IMAX, DTSHD, DTS, LPCM 2.0 192kHz 24b', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_txa1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_txa1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'EDID TXA1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'EDID TXA1', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'edida1', + 'unique_id': '000123456789_EDIDA1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_edid_txa1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 EDID TXA1', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_edid_txa1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'DD, DTS, LPCM 2.0 48kHz 24b', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_input_rx0-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_input_rx0', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Input RX0', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Input RX0', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'rx0', + 'unique_id': '000123456789_RX0', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_input_rx0-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Input RX0', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_input_rx0', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4K59.937 593MHz 422 BT2020 12b 2.2', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_input_rx1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_input_rx1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Input RX1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Input RX1', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'rx1', + 'unique_id': '000123456789_RX1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_input_rx1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Input RX1', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_input_rx1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'no signal', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_output_tx0-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_output_tx0', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Output TX0', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Output TX0', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'tx0', + 'unique_id': '000123456789_TX0', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_output_tx0-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Output TX0', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_output_tx0', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4K59.937 593MHz 422 BT2020 12b 2.2', + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_output_tx1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.hdfury_vrroom_02_output_tx1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Output TX1', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Output TX1', + 'platform': 'hdfury', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'tx1', + 'unique_id': '000123456789_TX1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor_entities[sensor.hdfury_vrroom_02_output_tx1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'HDFury VRROOM-02 Output TX1', + }), + 'context': , + 'entity_id': 'sensor.hdfury_vrroom_02_output_tx1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4K59.937 593MHz 422 BT2020 12b 2.2', + }) +# --- diff --git a/tests/components/hdfury/snapshots/test_switch.ambr b/tests/components/hdfury/snapshots/test_switch.ambr index f8666f7c3ad..ae50fbef067 100644 --- a/tests/components/hdfury/snapshots/test_switch.ambr +++ b/tests/components/hdfury/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto switch inputs', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HTPC mode RX0', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HTPC mode RX1', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HTPC mode RX2', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HTPC mode RX3', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Infrared', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute audio TX0', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute audio TX1', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'OLED display', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/hdfury/test_button.py b/tests/components/hdfury/test_button.py index 422e73b0d36..0845e183224 100644 --- a/tests/components/hdfury/test_button.py +++ b/tests/components/hdfury/test_button.py @@ -6,7 +6,8 @@ from hdfury import HDFuryError import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.const import Platform +from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS +from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.entity_registry as er @@ -47,9 +48,9 @@ async def test_button_presses( await setup_integration(hass, mock_config_entry, [Platform.BUTTON]) await hass.services.async_call( - "button", - "press", - {"entity_id": entity_id}, + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) @@ -67,10 +68,13 @@ async def test_button_press_error( await setup_integration(hass, mock_config_entry, [Platform.BUTTON]) - with pytest.raises(HomeAssistantError): + with pytest.raises( + HomeAssistantError, + match="An error occurred while communicating with HDFury device", + ): await hass.services.async_call( - "button", - "press", - {"entity_id": "button.hdfury_vrroom_02_restart"}, + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.hdfury_vrroom_02_restart"}, blocking=True, ) diff --git a/tests/components/hdfury/test_diagnostics.py b/tests/components/hdfury/test_diagnostics.py new file mode 100644 index 00000000000..c602e06ce25 --- /dev/null +++ b/tests/components/hdfury/test_diagnostics.py @@ -0,0 +1,31 @@ +"""Tests for the HDFury diagnostics.""" + +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.hdfury import PLATFORMS +from homeassistant.core import HomeAssistant +import homeassistant.helpers.entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry +from tests.components.diagnostics import get_diagnostics_for_config_entry +from tests.typing import ClientSessionGenerator + + +async def test_diagnostics( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test HDFury diagnostics.""" + + await setup_integration(hass, mock_config_entry, PLATFORMS) + + diagnostics = await get_diagnostics_for_config_entry( + hass, hass_client, mock_config_entry + ) + + assert diagnostics == snapshot diff --git a/tests/components/hdfury/test_select.py b/tests/components/hdfury/test_select.py index aabce4c9798..778511d1375 100644 --- a/tests/components/hdfury/test_select.py +++ b/tests/components/hdfury/test_select.py @@ -1,14 +1,25 @@ """Tests for the HDFury select platform.""" +from datetime import timedelta +from unittest.mock import AsyncMock + +from freezegun.api import FrozenDateTimeFactory +from hdfury import HDFuryError +import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.const import Platform +from homeassistant.components.select import ( + DOMAIN as SELECT_DOMAIN, + SERVICE_SELECT_OPTION, +) +from homeassistant.const import ATTR_ENTITY_ID, ATTR_OPTION, STATE_UNAVAILABLE, Platform from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.entity_registry as er from . import setup_integration -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform async def test_select_entities( @@ -21,3 +32,133 @@ async def test_select_entities( await setup_integration(hass, mock_config_entry, [Platform.SELECT]) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +async def test_select_operation_mode( + hass: HomeAssistant, + mock_hdfury_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test selecting operation mode.""" + + await setup_integration(hass, mock_config_entry, [Platform.SELECT]) + + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.hdfury_vrroom_02_operation_mode", + ATTR_OPTION: "1", + }, + blocking=True, + ) + + mock_hdfury_client.set_operation_mode.assert_awaited_once_with("1") + + +@pytest.mark.parametrize( + ("entity_id"), + [ + ("select.hdfury_vrroom_02_port_select_tx0"), + ("select.hdfury_vrroom_02_port_select_tx1"), + ], +) +async def test_select_tx_ports( + hass: HomeAssistant, + mock_hdfury_client: AsyncMock, + mock_config_entry: MockConfigEntry, + entity_id: str, +) -> None: + """Test selecting TX ports.""" + + await setup_integration(hass, mock_config_entry, [Platform.SELECT]) + + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: entity_id, + ATTR_OPTION: "1", + }, + blocking=True, + ) + + mock_hdfury_client.set_port_selection.assert_awaited() + + +async def test_select_operation_mode_error( + hass: HomeAssistant, + mock_hdfury_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test operation mode select raises HomeAssistantError.""" + + mock_hdfury_client.set_operation_mode.side_effect = HDFuryError() + + await setup_integration(hass, mock_config_entry, [Platform.SELECT]) + + with pytest.raises( + HomeAssistantError, + match="An error occurred while communicating with HDFury device", + ): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.hdfury_vrroom_02_operation_mode", + ATTR_OPTION: "1", + }, + blocking=True, + ) + + +async def test_select_ports_missing_state( + hass: HomeAssistant, + mock_hdfury_client: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test TX port selection fails when TX state is incomplete.""" + + mock_hdfury_client.get_info.return_value = { + "portseltx0": "0", + "portseltx1": None, + "opmode": "0", + } + + await setup_integration(hass, mock_config_entry, [Platform.SELECT]) + + with pytest.raises( + HomeAssistantError, + match="An error occurred while validating TX states", + ): + await hass.services.async_call( + SELECT_DOMAIN, + SERVICE_SELECT_OPTION, + { + ATTR_ENTITY_ID: "select.hdfury_vrroom_02_port_select_tx0", + ATTR_OPTION: "0", + }, + blocking=True, + ) + + +async def test_select_entities_unavailable_on_error( + hass: HomeAssistant, + mock_hdfury_client: AsyncMock, + mock_config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test API error causes entities to become unavailable.""" + + await setup_integration(hass, mock_config_entry, [Platform.SELECT]) + + mock_hdfury_client.get_info.side_effect = HDFuryError() + + freezer.tick(timedelta(seconds=61)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert ( + hass.states.get("select.hdfury_vrroom_02_port_select_tx0").state + == STATE_UNAVAILABLE + ) diff --git a/tests/components/hdfury/test_sensor.py b/tests/components/hdfury/test_sensor.py new file mode 100644 index 00000000000..e6c5fd523c7 --- /dev/null +++ b/tests/components/hdfury/test_sensor.py @@ -0,0 +1,25 @@ +"""Tests for the HDFury sensor platform.""" + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +import homeassistant.helpers.entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_sensor_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test HDFury sensor entities.""" + + await setup_integration(hass, mock_config_entry, [Platform.SENSOR]) + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) diff --git a/tests/components/hdfury/test_switch.py b/tests/components/hdfury/test_switch.py index eaf9aa42ead..96579d635b9 100644 --- a/tests/components/hdfury/test_switch.py +++ b/tests/components/hdfury/test_switch.py @@ -1,19 +1,28 @@ """Tests for the HDFury switch platform.""" +from datetime import timedelta from unittest.mock import AsyncMock +from freezegun.api import FrozenDateTimeFactory from hdfury import HDFuryError import pytest from syrupy.assertion import SnapshotAssertion -from homeassistant.const import Platform +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + STATE_UNAVAILABLE, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError import homeassistant.helpers.entity_registry as er from . import setup_integration -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform async def test_switch_entities( @@ -34,15 +43,15 @@ async def test_switch_entities( ( "switch.hdfury_vrroom_02_auto_switch_inputs", "set_auto_switch_inputs", - "turn_on", + SERVICE_TURN_ON, ), ( "switch.hdfury_vrroom_02_auto_switch_inputs", "set_auto_switch_inputs", - "turn_off", + SERVICE_TURN_OFF, ), - ("switch.hdfury_vrroom_02_oled_display", "set_oled", "turn_on"), - ("switch.hdfury_vrroom_02_oled_display", "set_oled", "turn_off"), + ("switch.hdfury_vrroom_02_oled_display", "set_oled", SERVICE_TURN_ON), + ("switch.hdfury_vrroom_02_oled_display", "set_oled", SERVICE_TURN_OFF), ], ) async def test_switch_turn_on_off( @@ -58,9 +67,9 @@ async def test_switch_turn_on_off( await setup_integration(hass, mock_config_entry, [Platform.SWITCH]) await hass.services.async_call( - "switch", + SWITCH_DOMAIN, service, - {"entity_id": entity_id}, + {ATTR_ENTITY_ID: entity_id}, blocking=True, ) @@ -70,8 +79,8 @@ async def test_switch_turn_on_off( @pytest.mark.parametrize( ("service", "method"), [ - ("turn_on", "set_auto_switch_inputs"), - ("turn_off", "set_auto_switch_inputs"), + (SERVICE_TURN_ON, "set_auto_switch_inputs"), + (SERVICE_TURN_OFF, "set_auto_switch_inputs"), ], ) async def test_switch_turn_error( @@ -92,8 +101,30 @@ async def test_switch_turn_error( match="An error occurred while communicating with HDFury device", ): await hass.services.async_call( - "switch", + SWITCH_DOMAIN, service, - {"entity_id": "switch.hdfury_vrroom_02_auto_switch_inputs"}, + {ATTR_ENTITY_ID: "switch.hdfury_vrroom_02_auto_switch_inputs"}, blocking=True, ) + + +async def test_switch_entities_unavailable_on_error( + hass: HomeAssistant, + mock_hdfury_client: AsyncMock, + mock_config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test API error causes entities to become unavailable.""" + + await setup_integration(hass, mock_config_entry, [Platform.SWITCH]) + + mock_hdfury_client.get_info.side_effect = HDFuryError() + + freezer.tick(timedelta(seconds=61)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert ( + hass.states.get("switch.hdfury_vrroom_02_auto_switch_inputs").state + == STATE_UNAVAILABLE + ) diff --git a/tests/components/hikvision/conftest.py b/tests/components/hikvision/conftest.py index 4964b1f8f32..d99e68a62a6 100644 --- a/tests/components/hikvision/conftest.py +++ b/tests/components/hikvision/conftest.py @@ -1,10 +1,11 @@ """Common fixtures for the Hikvision tests.""" -from collections.abc import Generator -from unittest.mock import AsyncMock, MagicMock, patch +from collections.abc import AsyncGenerator, Generator +from unittest.mock import MagicMock, patch import pytest +from homeassistant.components.hikvision import PLATFORMS from homeassistant.components.hikvision.const import DOMAIN from homeassistant.const import ( CONF_HOST, @@ -12,6 +13,7 @@ from homeassistant.const import ( CONF_PORT, CONF_SSL, CONF_USERNAME, + Platform, ) from tests.common import MockConfigEntry @@ -25,7 +27,20 @@ TEST_DEVICE_NAME = "Front Camera" @pytest.fixture -def mock_setup_entry() -> Generator[AsyncMock]: +def platforms() -> list[Platform]: + """Platforms, which should be loaded during the test.""" + return PLATFORMS + + +@pytest.fixture(autouse=True) +async def mock_patch_platforms(platforms: list[Platform]) -> AsyncGenerator[None]: + """Fixture to set up platforms for tests.""" + with patch(f"homeassistant.components.{DOMAIN}.PLATFORMS", platforms): + yield + + +@pytest.fixture +def mock_setup_entry() -> Generator[MagicMock]: """Override async_setup_entry.""" with patch( "homeassistant.components.hikvision.async_setup_entry", return_value=True @@ -58,7 +73,6 @@ def mock_hikcamera() -> Generator[MagicMock]: with ( patch( "homeassistant.components.hikvision.HikCamera", - autospec=True, ) as hikcamera_mock, patch( "homeassistant.components.hikvision.config_flow.HikCamera", @@ -80,6 +94,15 @@ def mock_hikcamera() -> Generator[MagicMock]: "2024-01-01T00:00:00Z", ) camera.get_event_triggers.return_value = {} + + # pyHik 0.4.0 methods + camera.get_channels.return_value = [1] + camera.get_snapshot.return_value = b"fake_image_data" + camera.get_stream_url.return_value = ( + f"rtsp://{TEST_USERNAME}:{TEST_PASSWORD}" + f"@{TEST_HOST}:554/Streaming/Channels/1" + ) + yield hikcamera_mock diff --git a/tests/components/hikvision/snapshots/test_binary_sensor.ambr b/tests/components/hikvision/snapshots/test_binary_sensor.ambr index 2d77654cd58..564e025e445 100644 --- a/tests/components/hikvision/snapshots/test_binary_sensor.ambr +++ b/tests/components/hikvision/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Line Crossing', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/hikvision/snapshots/test_camera.ambr b/tests/components/hikvision/snapshots/test_camera.ambr new file mode 100644 index 00000000000..00c5ba5dfb3 --- /dev/null +++ b/tests/components/hikvision/snapshots/test_camera.ambr @@ -0,0 +1,157 @@ +# serializer version: 1 +# name: test_all_entities[camera.front_camera-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'camera', + 'entity_category': None, + 'entity_id': 'camera.front_camera', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'hikvision', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': 'DS-2CD2142FWD-I20170101AAAA_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[camera.front_camera-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'access_token': '1caab5c3b3', + 'entity_picture': '/api/camera_proxy/camera.front_camera?token=1caab5c3b3', + 'friendly_name': 'Front Camera', + 'supported_features': , + }), + 'context': , + 'entity_id': 'camera.front_camera', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'idle', + }) +# --- +# name: test_nvr_entities[camera.front_camera_channel_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'camera', + 'entity_category': None, + 'entity_id': 'camera.front_camera_channel_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'hikvision', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': 'DS-2CD2142FWD-I20170101AAAA_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_nvr_entities[camera.front_camera_channel_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'access_token': '1caab5c3b3', + 'entity_picture': '/api/camera_proxy/camera.front_camera_channel_1?token=1caab5c3b3', + 'friendly_name': 'Front Camera channel 1', + 'supported_features': , + }), + 'context': , + 'entity_id': 'camera.front_camera_channel_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'idle', + }) +# --- +# name: test_nvr_entities[camera.front_camera_channel_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'camera', + 'entity_category': None, + 'entity_id': 'camera.front_camera_channel_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'hikvision', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': 'DS-2CD2142FWD-I20170101AAAA_2', + 'unit_of_measurement': None, + }) +# --- +# name: test_nvr_entities[camera.front_camera_channel_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'access_token': '1caab5c3b3', + 'entity_picture': '/api/camera_proxy/camera.front_camera_channel_2?token=1caab5c3b3', + 'friendly_name': 'Front Camera channel 2', + 'supported_features': , + }), + 'context': , + 'entity_id': 'camera.front_camera_channel_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'idle', + }) +# --- diff --git a/tests/components/hikvision/test_binary_sensor.py b/tests/components/hikvision/test_binary_sensor.py index 7c659c1c11a..88622889b34 100644 --- a/tests/components/hikvision/test_binary_sensor.py +++ b/tests/components/hikvision/test_binary_sensor.py @@ -17,6 +17,7 @@ from homeassistant.const import ( CONF_SSL, CONF_USERNAME, STATE_OFF, + Platform, ) from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant from homeassistant.helpers import ( @@ -39,6 +40,12 @@ from .conftest import ( from tests.common import MockConfigEntry, snapshot_platform +@pytest.fixture +def platforms() -> list[Platform]: + """Platforms, which should be loaded during the test.""" + return [Platform.BINARY_SENSOR] + + @pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_all_entities( hass: HomeAssistant, @@ -132,11 +139,11 @@ async def test_binary_sensor_nvr_device( await setup_integration(hass, mock_config_entry) - # NVR sensors should include channel number in name - state = hass.states.get("binary_sensor.front_camera_motion_1") + # NVR sensors are on per-channel devices + state = hass.states.get("binary_sensor.front_camera_channel_1_motion") assert state is not None - state = hass.states.get("binary_sensor.front_camera_motion_2") + state = hass.states.get("binary_sensor.front_camera_channel_2_motion") assert state is not None diff --git a/tests/components/hikvision/test_camera.py b/tests/components/hikvision/test_camera.py new file mode 100644 index 00000000000..7ae42aaf23e --- /dev/null +++ b/tests/components/hikvision/test_camera.py @@ -0,0 +1,165 @@ +"""Test Hikvision cameras.""" + +from unittest.mock import MagicMock, patch + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.camera import async_get_image, async_get_stream_source +from homeassistant.components.hikvision.const import DOMAIN +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import device_registry as dr, entity_registry as er + +from . import setup_integration +from .conftest import TEST_DEVICE_ID, TEST_DEVICE_NAME, TEST_HOST, TEST_PASSWORD + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.fixture +def platforms() -> list[Platform]: + """Return platforms to load during test.""" + return [Platform.CAMERA] + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_all_entities( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test all camera entities.""" + with patch("random.SystemRandom.getrandbits", return_value=123123123123): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_nvr_entities( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test NVR camera entities with multiple channels.""" + mock_hikcamera.return_value.get_type = "NVR" + mock_hikcamera.return_value.get_channels.return_value = [1, 2] + + with patch("random.SystemRandom.getrandbits", return_value=123123123123): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +async def test_camera_device_info( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, + device_registry: dr.DeviceRegistry, +) -> None: + """Test camera is linked to device.""" + await setup_integration(hass, mock_config_entry) + + device_entry = device_registry.async_get_device( + identifiers={(DOMAIN, TEST_DEVICE_ID)} + ) + assert device_entry is not None + assert device_entry.name == TEST_DEVICE_NAME + assert device_entry.manufacturer == "Hikvision" + assert device_entry.model == "Camera" + + +async def test_camera_no_channels_creates_single_camera( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, +) -> None: + """Test camera created when device returns no channels.""" + mock_hikcamera.return_value.get_channels.return_value = [] + + await setup_integration(hass, mock_config_entry) + + # Single camera should be created for channel 1 + states = hass.states.async_entity_ids("camera") + assert len(states) == 1 + + state = hass.states.get("camera.front_camera") + assert state is not None + + +async def test_camera_image( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, +) -> None: + """Test getting camera image.""" + await setup_integration(hass, mock_config_entry) + + image = await async_get_image(hass, "camera.front_camera") + assert image.content == b"fake_image_data" + + # Verify get_snapshot was called with channel 1 + mock_hikcamera.return_value.get_snapshot.assert_called_with(1) + + +async def test_camera_image_error( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, +) -> None: + """Test camera image error handling.""" + mock_hikcamera.return_value.get_snapshot.side_effect = Exception("Connection error") + + await setup_integration(hass, mock_config_entry) + + with pytest.raises(HomeAssistantError, match="Error getting image"): + await async_get_image(hass, "camera.front_camera") + + +async def test_camera_stream_source( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, +) -> None: + """Test camera stream source URL.""" + await setup_integration(hass, mock_config_entry) + + stream_url = await async_get_stream_source(hass, "camera.front_camera") + + # Verify RTSP URL from library + assert stream_url is not None + assert stream_url.startswith("rtsp://") + assert f"@{TEST_HOST}:554/Streaming/Channels/1" in stream_url + + # Verify get_stream_url was called with channel 1 + mock_hikcamera.return_value.get_stream_url.assert_called_with(1) + + +async def test_camera_stream_source_nvr( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_hikcamera: MagicMock, +) -> None: + """Test NVR camera stream source URL.""" + mock_hikcamera.return_value.get_type = "NVR" + mock_hikcamera.return_value.get_channels.return_value = [2] + mock_hikcamera.return_value.get_stream_url.return_value = ( + f"rtsp://admin:{TEST_PASSWORD}@{TEST_HOST}:554/Streaming/Channels/201" + ) + + await setup_integration(hass, mock_config_entry) + + stream_url = await async_get_stream_source(hass, "camera.front_camera_channel_2") + + # NVR channel 2 should use stream channel 201 + assert stream_url is not None + assert f"@{TEST_HOST}:554/Streaming/Channels/201" in stream_url + + # Verify get_stream_url was called with channel 2 + mock_hikcamera.return_value.get_stream_url.assert_called_with(2) diff --git a/tests/components/homeassistant/triggers/conftest.py b/tests/components/homeassistant/triggers/conftest.py deleted file mode 100644 index 9dabbad99c9..00000000000 --- a/tests/components/homeassistant/triggers/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Conftest for HA triggers.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/homee/snapshots/test_alarm_control_panel.ambr b/tests/components/homee/snapshots/test_alarm_control_panel.ambr index 8095831965a..1b0621da26c 100644 --- a/tests/components/homee/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/homee/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_binary_sensor.ambr b/tests/components/homee/snapshots/test_binary_sensor.ambr index f9f905bfc44..f676aca1d3b 100644 --- a/tests/components/homee/snapshots/test_binary_sensor.ambr +++ b/tests/components/homee/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Blackout', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Blackout', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flood', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High temperature', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load', 'options': dict({ }), 'original_device_class': None, @@ -460,6 +469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': , @@ -509,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low temperature', 'options': dict({ }), 'original_device_class': , @@ -558,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Malfunction', 'options': dict({ }), 'original_device_class': , @@ -607,6 +619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum level', 'options': dict({ }), 'original_device_class': , @@ -656,6 +669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum level', 'options': dict({ }), 'original_device_class': , @@ -705,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -754,6 +769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor blocked', 'options': dict({ }), 'original_device_class': , @@ -803,6 +819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opening', 'options': dict({ }), 'original_device_class': , @@ -852,6 +869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -901,6 +919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overload', 'options': dict({ }), 'original_device_class': , @@ -950,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -999,6 +1019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1048,6 +1069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence', 'options': dict({ }), 'original_device_class': , @@ -1097,6 +1119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain', 'options': dict({ }), 'original_device_class': , @@ -1146,6 +1169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Replace filter', 'options': dict({ }), 'original_device_class': , @@ -1195,6 +1219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1244,6 +1269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage', 'options': dict({ }), 'original_device_class': , @@ -1293,6 +1319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Surge', 'options': dict({ }), 'original_device_class': , @@ -1342,6 +1369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1391,6 +1419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage drop', 'options': dict({ }), 'original_device_class': , @@ -1440,6 +1469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ }), 'original_device_class': , @@ -1489,6 +1519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1538,6 +1569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Blackout', 'options': dict({ }), 'original_device_class': , @@ -1587,6 +1619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -1636,6 +1669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ }), 'original_device_class': , @@ -1685,6 +1719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flood', 'options': dict({ }), 'original_device_class': , @@ -1734,6 +1769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High temperature', 'options': dict({ }), 'original_device_class': , @@ -1783,6 +1819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leak', 'options': dict({ }), 'original_device_class': , @@ -1832,6 +1869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load', 'options': dict({ }), 'original_device_class': None, @@ -1880,6 +1918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': , @@ -1929,6 +1968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low temperature', 'options': dict({ }), 'original_device_class': , @@ -1978,6 +2018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Malfunction', 'options': dict({ }), 'original_device_class': , @@ -2027,6 +2068,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum level', 'options': dict({ }), 'original_device_class': , @@ -2076,6 +2118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum level', 'options': dict({ }), 'original_device_class': , @@ -2125,6 +2168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -2174,6 +2218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor blocked', 'options': dict({ }), 'original_device_class': , @@ -2223,6 +2268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opening', 'options': dict({ }), 'original_device_class': , @@ -2272,6 +2318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -2321,6 +2368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overload', 'options': dict({ }), 'original_device_class': , @@ -2370,6 +2418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -2419,6 +2468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -2468,6 +2518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence', 'options': dict({ }), 'original_device_class': , @@ -2517,6 +2568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain', 'options': dict({ }), 'original_device_class': , @@ -2566,6 +2618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Replace filter', 'options': dict({ }), 'original_device_class': , @@ -2615,6 +2668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -2664,6 +2718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storage', 'options': dict({ }), 'original_device_class': , @@ -2713,6 +2768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Surge', 'options': dict({ }), 'original_device_class': , @@ -2762,6 +2818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2811,6 +2868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage drop', 'options': dict({ }), 'original_device_class': , @@ -2860,6 +2918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/homee/snapshots/test_button.ambr b/tests/components/homee/snapshots/test_button.ambr index eea7e8ffd06..daf9ec55029 100644 --- a/tests/components/homee/snapshots/test_button.ambr +++ b/tests/components/homee/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Automatic mode', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Briefly open', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identification mode', 'options': dict({ }), 'original_device_class': , @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Impulse 1', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Impulse 2', 'options': dict({ }), 'original_device_class': None, @@ -309,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -357,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Open partially', 'options': dict({ }), 'original_device_class': None, @@ -405,6 +413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Open permanently', 'options': dict({ }), 'original_device_class': None, @@ -453,6 +462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset meter 1', 'options': dict({ }), 'original_device_class': None, @@ -501,6 +511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset meter 2', 'options': dict({ }), 'original_device_class': None, @@ -549,6 +560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilate', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_climate.ambr b/tests/components/homee/snapshots/test_climate.ambr index 3a1ec23a56d..ae1d7748c43 100644 --- a/tests/components/homee/snapshots/test_climate.ambr +++ b/tests/components/homee/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -92,6 +93,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -158,6 +160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -231,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -309,6 +313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_event.ambr b/tests/components/homee/snapshots/test_event.ambr index 981b6263984..e5765c9274e 100644 --- a/tests/components/homee/snapshots/test_event.ambr +++ b/tests/components/homee/snapshots/test_event.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen Light', 'options': dict({ }), 'original_device_class': , @@ -87,6 +88,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': , @@ -155,6 +157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Up/down remote', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/homee/snapshots/test_fan.ambr b/tests/components/homee/snapshots/test_fan.ambr index b6d77582aaf..730225563d5 100644 --- a/tests/components/homee/snapshots/test_fan.ambr +++ b/tests/components/homee/snapshots/test_fan.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_light.ambr b/tests/components/homee/snapshots/test_light.ambr index 2f22d95ae8d..06326606039 100644 --- a/tests/components/homee/snapshots/test_light.ambr +++ b/tests/components/homee/snapshots/test_light.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -110,6 +111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light 1', 'options': dict({ }), 'original_device_class': None, @@ -193,6 +195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light 2', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light 3', 'options': dict({ }), 'original_device_class': None, @@ -319,6 +323,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light 4', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_lock.ambr b/tests/components/homee/snapshots/test_lock.ambr index 41563d6be41..4baac376550 100644 --- a/tests/components/homee/snapshots/test_lock.ambr +++ b/tests/components/homee/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_number.ambr b/tests/components/homee/snapshots/test_number.ambr index 5f0981bae7f..9ca05eb3f46 100644 --- a/tests/components/homee/snapshots/test_number.ambr +++ b/tests/components/homee/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button brightness (active)', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button brightness (dimmed)', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display brightness (active)', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display brightness (dimmed)', 'options': dict({ }), 'original_device_class': None, @@ -257,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Down-movement duration', 'options': dict({ }), 'original_device_class': , @@ -316,6 +321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Down position', 'options': dict({ }), 'original_device_class': None, @@ -374,6 +380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Down slat position', 'options': dict({ }), 'original_device_class': None, @@ -432,6 +439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'End position', 'options': dict({ }), 'original_device_class': None, @@ -489,6 +497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External temperature offset', 'options': dict({ }), 'original_device_class': None, @@ -547,6 +556,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Floor temperature offset', 'options': dict({ }), 'original_device_class': None, @@ -605,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum slat angle', 'options': dict({ }), 'original_device_class': None, @@ -663,6 +674,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum slat angle', 'options': dict({ }), 'original_device_class': None, @@ -721,6 +733,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm delay', 'options': dict({ }), 'original_device_class': , @@ -780,6 +793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Polling interval', 'options': dict({ }), 'original_device_class': , @@ -839,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Slat steps', 'options': dict({ }), 'original_device_class': None, @@ -896,6 +911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Slat turn duration', 'options': dict({ }), 'original_device_class': , @@ -955,6 +971,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': None, @@ -1013,6 +1030,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature report interval', 'options': dict({ }), 'original_device_class': , @@ -1072,6 +1090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Threshold for wind trigger', 'options': dict({ }), 'original_device_class': , @@ -1131,6 +1150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Up-movement duration', 'options': dict({ }), 'original_device_class': , @@ -1190,6 +1210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wake-up interval', 'options': dict({ }), 'original_device_class': , @@ -1249,6 +1270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window open sensibility', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_select.ambr b/tests/components/homee/snapshots/test_select.ambr index 49cb8612522..8bd4f425a34 100644 --- a/tests/components/homee/snapshots/test_select.ambr +++ b/tests/components/homee/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Displayed temperature', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Repeater mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_sensor.ambr b/tests/components/homee/snapshots/test_sensor.ambr index 4e4eb98f28c..5772bdc128b 100644 --- a/tests/components/homee/snapshots/test_sensor.ambr +++ b/tests/components/homee/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dawn', 'options': dict({ }), 'original_device_class': , @@ -240,6 +244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -296,6 +301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -352,6 +358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -408,6 +415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exhaust motor speed', 'options': dict({ }), 'original_device_class': None, @@ -460,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -516,6 +525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Floor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -572,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -625,6 +636,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': None, @@ -677,6 +689,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance 1', 'options': dict({ }), 'original_device_class': , @@ -730,6 +743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance 2', 'options': dict({ }), 'original_device_class': , @@ -783,6 +797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor humidity', 'options': dict({ }), 'original_device_class': , @@ -836,6 +851,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -892,6 +908,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intake motor speed', 'options': dict({ }), 'original_device_class': None, @@ -944,6 +961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1000,6 +1018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link quality', 'options': dict({ }), 'original_device_class': None, @@ -1066,6 +1085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Node state', 'options': dict({ }), 'original_device_class': , @@ -1133,6 +1153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating hours', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1189,6 +1210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity', 'options': dict({ }), 'original_device_class': , @@ -1242,6 +1264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1298,6 +1321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position', 'options': dict({ }), 'original_device_class': None, @@ -1356,6 +1380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -1414,6 +1439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1470,6 +1496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1526,6 +1553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1582,6 +1610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1638,6 +1667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1694,6 +1724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ultraviolet', 'options': dict({ }), 'original_device_class': None, @@ -1745,6 +1776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1801,6 +1833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1857,6 +1890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1920,6 +1954,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window position', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/homee/snapshots/test_siren.ambr b/tests/components/homee/snapshots/test_siren.ambr index 90f43834dc9..922f4cd9b43 100644 --- a/tests/components/homee/snapshots/test_siren.ambr +++ b/tests/components/homee/snapshots/test_siren.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homee/snapshots/test_switch.ambr b/tests/components/homee/snapshots/test_switch.ambr index c8d68301884..024b09d8366 100644 --- a/tests/components/homee/snapshots/test_switch.ambr +++ b/tests/components/homee/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual operation', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Watchdog', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/homee/snapshots/test_valve.ambr b/tests/components/homee/snapshots/test_valve.ambr index bdf6d9f381c..e61794f9f5a 100644 --- a/tests/components/homee/snapshots/test_valve.ambr +++ b/tests/components/homee/snapshots/test_valve.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/homee/test_sensor.py b/tests/components/homee/test_sensor.py index b51b3a23b75..0e7bde2e76b 100644 --- a/tests/components/homee/test_sensor.py +++ b/tests/components/homee/test_sensor.py @@ -10,20 +10,17 @@ from homeassistant.components.homeassistant import ( SERVICE_UPDATE_ENTITY, ) from homeassistant.components.homee.const import ( - DOMAIN, OPEN_CLOSE_MAP, OPEN_CLOSE_MAP_REVERSED, WINDOW_MAP, WINDOW_MAP_REVERSED, ) -from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er, issue_registry as ir +from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from . import async_update_attribute_value, build_mock_node, setup_integration -from .conftest import HOMEE_ID from tests.common import MockConfigEntry, snapshot_platform @@ -100,79 +97,6 @@ async def test_window_position( ) -@pytest.mark.parametrize( - ("disabler", "expected_entity", "expected_issue"), - [ - (None, False, False), - (er.RegistryEntryDisabler.USER, True, True), - ], -) -async def test_sensor_deprecation( - hass: HomeAssistant, - mock_homee: MagicMock, - mock_config_entry: MockConfigEntry, - issue_registry: ir.IssueRegistry, - entity_registry: er.EntityRegistry, - disabler: er.RegistryEntryDisabler, - expected_entity: bool, - expected_issue: bool, -) -> None: - """Test sensor deprecation issue.""" - entity_uid = f"{HOMEE_ID}-1-9" - entity_id = "test_multisensor_valve_position" - entity_registry.async_get_or_create( - SENSOR_DOMAIN, - DOMAIN, - entity_uid, - suggested_object_id=entity_id, - disabled_by=disabler, - ) - - with patch( - "homeassistant.components.homee.sensor.entity_used_in", return_value=True - ): - await setup_sensor(hass, mock_homee, mock_config_entry) - - assert (entity_registry.async_get(f"sensor.{entity_id}") is None) is expected_entity - assert ( - issue_registry.async_get_issue( - domain=DOMAIN, - issue_id=f"deprecated_entity_{entity_uid}", - ) - is None - ) is expected_issue - - -async def test_sensor_deprecation_unused_entity( - hass: HomeAssistant, - mock_homee: MagicMock, - mock_config_entry: MockConfigEntry, - issue_registry: ir.IssueRegistry, - entity_registry: er.EntityRegistry, -) -> None: - """Test sensor deprecation issue.""" - entity_uid = f"{HOMEE_ID}-1-9" - entity_id = "test_multisensor_valve_position" - entity_registry.async_get_or_create( - SENSOR_DOMAIN, - DOMAIN, - entity_uid, - suggested_object_id=entity_id, - disabled_by=None, - ) - - await setup_sensor(hass, mock_homee, mock_config_entry) - - assert entity_registry.async_get(f"sensor.{entity_id}") is not None - assert ( - issue_registry.async_get_issue( - domain=DOMAIN, - issue_id=f"deprecated_entity_{entity_uid}", - ) - is None - ) - - async def test_entity_connection_listener( hass: HomeAssistant, mock_homee: MagicMock, diff --git a/tests/components/homekit/test_get_accessories.py b/tests/components/homekit/test_get_accessories.py index de5cda71513..77029f5d5dc 100644 --- a/tests/components/homekit/test_get_accessories.py +++ b/tests/components/homekit/test_get_accessories.py @@ -20,6 +20,13 @@ from homeassistant.components.homekit.const import ( TYPE_SWITCH, TYPE_VALVE, ) +from homeassistant.components.homekit.type_sensors import ( + AirQualitySensor, + CarbonDioxideSensor, + PM10Sensor, + PM25Sensor, + TemperatureSensor, +) from homeassistant.components.media_player import ( MediaPlayerDeviceClass, MediaPlayerEntityFeature, @@ -42,6 +49,20 @@ from homeassistant.const import ( from homeassistant.core import State +def get_identified_type(entity_id, attrs, config=None): + """Helper to return the accessory type name selected by get_accessory.""" + + def passthrough(type: type): + return lambda *args, **kwargs: type + + # Patch TYPES so that get_accessory returns a type instead of an instance. + with patch.dict( + TYPES, {type_name: passthrough(v) for type_name, v in TYPES.items()} + ): + entity_state = State(entity_id, "irrelevant", attrs) + return get_accessory(None, None, entity_state, 2, config or {}) + + def test_not_supported(caplog: pytest.LogCaptureFixture) -> None: """Test if none is returned if entity isn't supported.""" # not supported entity @@ -425,3 +446,58 @@ def test_type_camera(type_name, entity_id, state, attrs) -> None: entity_state = State(entity_id, state, attrs) get_accessory(None, None, entity_state, 2, {}) assert mock_type.called + + +@pytest.mark.parametrize( + ("expected_type", "entity_id", "attrs"), + [ + ( + PM10Sensor, + "sensor.air_quality_pm25", + {ATTR_DEVICE_CLASS: SensorDeviceClass.PM10}, + ), + ( + PM25Sensor, + "sensor.air_quality_pm10", + {ATTR_DEVICE_CLASS: SensorDeviceClass.PM25}, + ), + ( + AirQualitySensor, + "sensor.co2_sensor", + {ATTR_DEVICE_CLASS: SensorDeviceClass.GAS}, + ), + ( + CarbonDioxideSensor, + "sensor.air_quality_gas", + {ATTR_DEVICE_CLASS: SensorDeviceClass.CO2}, + ), + ( + TemperatureSensor, + "sensor.random_sensor", + {ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE}, + ), + ], +) +def test_explicit_device_class_takes_precedence( + expected_type, entity_id, attrs +) -> None: + """Test that explicit device_class takes precedence over entity_id hints.""" + identified_type = get_identified_type(entity_id, attrs=attrs) + assert identified_type == expected_type + + +@pytest.mark.parametrize( + ("expected_type", "entity_id", "attrs"), + [ + (PM10Sensor, "sensor.air_quality_pm10", {}), + (PM25Sensor, "sensor.air_quality_pm25", {}), + (AirQualitySensor, "sensor.air_quality_gas", {}), + (CarbonDioxideSensor, "sensor.airmeter_co2", {}), + ], +) +def test_entity_id_fallback_when_no_device_class( + expected_type, entity_id, attrs +) -> None: + """Test that entity_id is used as fallback when device_class is not set.""" + identified_type = get_identified_type(entity_id, attrs=attrs) + assert identified_type == expected_type diff --git a/tests/components/homekit_controller/snapshots/test_init.ambr b/tests/components/homekit_controller/snapshots/test_init.ambr index ea9c638c022..1745db8051a 100644 --- a/tests/components/homekit_controller/snapshots/test_init.ambr +++ b/tests/components/homekit_controller/snapshots/test_init.ambr @@ -57,6 +57,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Identify', 'options': dict({ }), 'original_device_class': , @@ -104,6 +105,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 AirPurifier', 'options': dict({ }), 'original_device_class': None, @@ -158,6 +160,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Air Purifier Mode', 'options': dict({ }), 'original_device_class': None, @@ -210,6 +213,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Air Purifier Status', 'options': dict({ }), 'original_device_class': , @@ -260,6 +264,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Air Quality', 'options': dict({ }), 'original_device_class': , @@ -306,6 +311,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -352,6 +358,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 PM2.5 Density', 'options': dict({ }), 'original_device_class': , @@ -406,6 +413,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Thread Capabilities', 'options': dict({ }), 'original_device_class': , @@ -467,6 +475,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Thread Status', 'options': dict({ }), 'original_device_class': , @@ -519,6 +528,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Lock Physical Controls', 'options': dict({ }), 'original_device_class': None, @@ -561,6 +571,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Mute', 'options': dict({ }), 'original_device_class': None, @@ -603,6 +614,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Airversa AP2 1808 Sleep Mode', 'options': dict({ }), 'original_device_class': None, @@ -686,6 +698,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufy HomeBase2-0AAA Identify', 'options': dict({ }), 'original_device_class': , @@ -766,6 +779,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-0000 Motion Sensor', 'options': dict({ }), 'original_device_class': , @@ -809,6 +823,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-0000 Identify', 'options': dict({ }), 'original_device_class': , @@ -852,6 +867,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-0000', 'options': dict({ }), 'original_device_class': None, @@ -897,6 +913,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-0000 Battery', 'options': dict({ }), 'original_device_class': , @@ -943,6 +960,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-0000 Mute', 'options': dict({ }), 'original_device_class': None, @@ -1022,6 +1040,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Motion Sensor', 'options': dict({ }), 'original_device_class': , @@ -1065,6 +1084,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Identify', 'options': dict({ }), 'original_device_class': , @@ -1108,6 +1128,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A', 'options': dict({ }), 'original_device_class': None, @@ -1153,6 +1174,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Battery', 'options': dict({ }), 'original_device_class': , @@ -1199,6 +1221,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Mute', 'options': dict({ }), 'original_device_class': None, @@ -1278,6 +1301,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Motion Sensor', 'options': dict({ }), 'original_device_class': , @@ -1321,6 +1345,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Identify', 'options': dict({ }), 'original_device_class': , @@ -1364,6 +1389,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A', 'options': dict({ }), 'original_device_class': None, @@ -1409,6 +1435,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Battery', 'options': dict({ }), 'original_device_class': , @@ -1455,6 +1482,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'eufyCam2-000A Mute', 'options': dict({ }), 'original_device_class': None, @@ -1538,6 +1566,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara-Hub-E1-00A0 Security System', 'options': dict({ }), 'original_device_class': None, @@ -1584,6 +1613,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara-Hub-E1-00A0 Identify', 'options': dict({ }), 'original_device_class': , @@ -1632,6 +1662,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara-Hub-E1-00A0 Volume', 'options': dict({ }), 'original_device_class': None, @@ -1678,6 +1709,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara-Hub-E1-00A0 Pairing Mode', 'options': dict({ }), 'original_device_class': None, @@ -1757,6 +1789,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Contact Sensor', 'options': dict({ }), 'original_device_class': , @@ -1800,6 +1833,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Contact Sensor Identify', 'options': dict({ }), 'original_device_class': , @@ -1845,6 +1879,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Contact Sensor Battery Sensor', 'options': dict({ }), 'original_device_class': , @@ -1932,6 +1967,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara Hub-1563 Security System', 'options': dict({ }), 'original_device_class': None, @@ -1978,6 +2014,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara Hub-1563 Identify', 'options': dict({ }), 'original_device_class': , @@ -2030,6 +2067,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara Hub-1563 Lightbulb-1563', 'options': dict({ }), 'original_device_class': None, @@ -2093,6 +2131,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara Hub-1563 Volume', 'options': dict({ }), 'original_device_class': None, @@ -2139,6 +2178,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Aqara Hub-1563 Pairing Mode', 'options': dict({ }), 'original_device_class': None, @@ -2222,6 +2262,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Programmable Switch Identify', 'options': dict({ }), 'original_device_class': , @@ -2267,6 +2308,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Programmable Switch Battery Sensor', 'options': dict({ }), 'original_device_class': , @@ -2354,6 +2396,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Motion', 'options': dict({ }), 'original_device_class': , @@ -2397,6 +2440,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Identify', 'options': dict({ }), 'original_device_class': , @@ -2440,6 +2484,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0', 'options': dict({ }), 'original_device_class': None, @@ -2492,6 +2537,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Nightlight', 'options': dict({ }), 'original_device_class': None, @@ -2552,6 +2598,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Air Quality', 'options': dict({ }), 'original_device_class': , @@ -2598,6 +2645,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Battery', 'options': dict({ }), 'original_device_class': , @@ -2646,6 +2694,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Humidity', 'options': dict({ }), 'original_device_class': , @@ -2693,6 +2742,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2741,6 +2791,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Mute', 'options': dict({ }), 'original_device_class': None, @@ -2783,6 +2834,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'ArloBabyA0 Mute', 'options': dict({ }), 'original_device_class': None, @@ -2866,6 +2918,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Identify', 'options': dict({ }), 'original_device_class': , @@ -2911,6 +2964,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2961,6 +3015,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3011,6 +3066,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Energy kWh', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3061,6 +3117,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Energy kWh', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3111,6 +3168,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3161,6 +3219,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3209,6 +3268,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Outlet A', 'options': dict({ }), 'original_device_class': None, @@ -3252,6 +3312,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'InWall Outlet-0394DE Outlet B', 'options': dict({ }), 'original_device_class': None, @@ -3336,6 +3397,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement', 'options': dict({ }), 'original_device_class': , @@ -3379,6 +3441,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Identify', 'options': dict({ }), 'original_device_class': , @@ -3424,6 +3487,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3509,6 +3573,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': , @@ -3552,6 +3617,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': , @@ -3595,6 +3661,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Clear Hold', 'options': dict({ }), 'original_device_class': None, @@ -3637,6 +3704,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Identify', 'options': dict({ }), 'original_device_class': , @@ -3691,6 +3759,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': None, @@ -3757,6 +3826,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Mode', 'options': dict({ }), 'original_device_class': None, @@ -3809,6 +3879,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -3857,6 +3928,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -3904,6 +3976,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3989,6 +4062,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen', 'options': dict({ }), 'original_device_class': , @@ -4032,6 +4106,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Identify', 'options': dict({ }), 'original_device_class': , @@ -4077,6 +4152,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4162,6 +4238,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Porch', 'options': dict({ }), 'original_device_class': , @@ -4205,6 +4282,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Porch Identify', 'options': dict({ }), 'original_device_class': , @@ -4250,6 +4328,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Porch Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4339,6 +4418,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Motion', 'options': dict({ }), 'original_device_class': , @@ -4382,6 +4462,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Occupancy', 'options': dict({ }), 'original_device_class': , @@ -4425,6 +4506,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Identify', 'options': dict({ }), 'original_device_class': , @@ -4470,6 +4552,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Battery', 'options': dict({ }), 'original_device_class': , @@ -4518,6 +4601,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4603,6 +4687,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Window 1 Contact', 'options': dict({ }), 'original_device_class': , @@ -4646,6 +4731,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Window 1 Motion', 'options': dict({ }), 'original_device_class': , @@ -4689,6 +4775,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Window 1 Occupancy', 'options': dict({ }), 'original_device_class': , @@ -4732,6 +4819,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Window 1 Identify', 'options': dict({ }), 'original_device_class': , @@ -4777,6 +4865,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Window 1 Battery', 'options': dict({ }), 'original_device_class': , @@ -4860,6 +4949,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Deck Door Contact', 'options': dict({ }), 'original_device_class': , @@ -4903,6 +4993,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Deck Door Motion', 'options': dict({ }), 'original_device_class': , @@ -4946,6 +5037,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Deck Door Occupancy', 'options': dict({ }), 'original_device_class': , @@ -4989,6 +5081,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Deck Door Identify', 'options': dict({ }), 'original_device_class': , @@ -5034,6 +5127,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Deck Door Battery', 'options': dict({ }), 'original_device_class': , @@ -5117,6 +5211,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Front Door Contact', 'options': dict({ }), 'original_device_class': , @@ -5160,6 +5255,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Front Door Motion', 'options': dict({ }), 'original_device_class': , @@ -5203,6 +5299,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Front Door Occupancy', 'options': dict({ }), 'original_device_class': , @@ -5246,6 +5343,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Front Door Identify', 'options': dict({ }), 'original_device_class': , @@ -5291,6 +5389,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Front Door Battery', 'options': dict({ }), 'original_device_class': , @@ -5374,6 +5473,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Garage Door Contact', 'options': dict({ }), 'original_device_class': , @@ -5417,6 +5517,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Garage Door Motion', 'options': dict({ }), 'original_device_class': , @@ -5460,6 +5561,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Garage Door Occupancy', 'options': dict({ }), 'original_device_class': , @@ -5503,6 +5605,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Garage Door Identify', 'options': dict({ }), 'original_device_class': , @@ -5548,6 +5651,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Garage Door Battery', 'options': dict({ }), 'original_device_class': , @@ -5631,6 +5735,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Motion', 'options': dict({ }), 'original_device_class': , @@ -5674,6 +5779,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Occupancy', 'options': dict({ }), 'original_device_class': , @@ -5717,6 +5823,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Identify', 'options': dict({ }), 'original_device_class': , @@ -5762,6 +5869,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Battery', 'options': dict({ }), 'original_device_class': , @@ -5810,6 +5918,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5895,6 +6004,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Window 1 Contact', 'options': dict({ }), 'original_device_class': , @@ -5938,6 +6048,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Window 1 Motion', 'options': dict({ }), 'original_device_class': , @@ -5981,6 +6092,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Window 1 Occupancy', 'options': dict({ }), 'original_device_class': , @@ -6024,6 +6136,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Window 1 Identify', 'options': dict({ }), 'original_device_class': , @@ -6069,6 +6182,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Window 1 Battery', 'options': dict({ }), 'original_device_class': , @@ -6152,6 +6266,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Loft window Contact', 'options': dict({ }), 'original_device_class': , @@ -6195,6 +6310,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Loft window Motion', 'options': dict({ }), 'original_device_class': , @@ -6238,6 +6354,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Loft window Occupancy', 'options': dict({ }), 'original_device_class': , @@ -6281,6 +6398,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Loft window Identify', 'options': dict({ }), 'original_device_class': , @@ -6326,6 +6444,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Loft window Battery', 'options': dict({ }), 'original_device_class': , @@ -6409,6 +6528,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Motion', 'options': dict({ }), 'original_device_class': , @@ -6452,6 +6572,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Occupancy', 'options': dict({ }), 'original_device_class': , @@ -6495,6 +6616,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Identify', 'options': dict({ }), 'original_device_class': , @@ -6540,6 +6662,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Battery', 'options': dict({ }), 'original_device_class': , @@ -6588,6 +6711,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6673,6 +6797,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Window Contact', 'options': dict({ }), 'original_device_class': , @@ -6716,6 +6841,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Window Motion', 'options': dict({ }), 'original_device_class': , @@ -6759,6 +6885,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Window Occupancy', 'options': dict({ }), 'original_device_class': , @@ -6802,6 +6929,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Window Identify', 'options': dict({ }), 'original_device_class': , @@ -6847,6 +6975,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master BR Window Battery', 'options': dict({ }), 'original_device_class': , @@ -6930,6 +7059,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat Clear Hold', 'options': dict({ }), 'original_device_class': None, @@ -6972,6 +7102,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat Identify', 'options': dict({ }), 'original_device_class': , @@ -7028,6 +7159,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat', 'options': dict({ }), 'original_device_class': None, @@ -7096,6 +7228,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat Current Mode', 'options': dict({ }), 'original_device_class': None, @@ -7148,6 +7281,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -7196,6 +7330,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -7243,6 +7378,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Thermostat Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7328,6 +7464,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Motion', 'options': dict({ }), 'original_device_class': , @@ -7371,6 +7508,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Occupancy', 'options': dict({ }), 'original_device_class': , @@ -7414,6 +7552,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Identify', 'options': dict({ }), 'original_device_class': , @@ -7459,6 +7598,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Battery', 'options': dict({ }), 'original_device_class': , @@ -7507,6 +7647,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7592,6 +7733,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Window Contact', 'options': dict({ }), 'original_device_class': , @@ -7635,6 +7777,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Window Motion', 'options': dict({ }), 'original_device_class': , @@ -7678,6 +7821,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Window Occupancy', 'options': dict({ }), 'original_device_class': , @@ -7721,6 +7865,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Window Identify', 'options': dict({ }), 'original_device_class': , @@ -7766,6 +7911,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Upstairs BR Window Battery', 'options': dict({ }), 'original_device_class': , @@ -7853,6 +7999,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': , @@ -7896,6 +8043,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': , @@ -7939,6 +8087,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Clear Hold', 'options': dict({ }), 'original_device_class': None, @@ -7981,6 +8130,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Identify', 'options': dict({ }), 'original_device_class': , @@ -8035,6 +8185,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': None, @@ -8101,6 +8252,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Mode', 'options': dict({ }), 'original_device_class': None, @@ -8153,6 +8305,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -8201,6 +8354,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -8248,6 +8402,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8337,6 +8492,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement', 'options': dict({ }), 'original_device_class': , @@ -8380,6 +8536,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Basement Identify', 'options': dict({ }), 'original_device_class': , @@ -8460,6 +8617,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Identify', 'options': dict({ }), 'original_device_class': , @@ -8514,6 +8672,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW', 'options': dict({ }), 'original_device_class': None, @@ -8579,6 +8738,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -8627,6 +8787,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -8674,6 +8835,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HomeW Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8759,6 +8921,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen', 'options': dict({ }), 'original_device_class': , @@ -8802,6 +8965,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Identify', 'options': dict({ }), 'original_device_class': , @@ -8847,6 +9011,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8932,6 +9097,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Porch', 'options': dict({ }), 'original_device_class': , @@ -8975,6 +9141,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Porch Identify', 'options': dict({ }), 'original_device_class': , @@ -9020,6 +9187,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Porch Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9109,6 +9277,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Motion', 'options': dict({ }), 'original_device_class': , @@ -9152,6 +9321,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Occupancy', 'options': dict({ }), 'original_device_class': , @@ -9195,6 +9365,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Clear Hold', 'options': dict({ }), 'original_device_class': None, @@ -9237,6 +9408,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Identify', 'options': dict({ }), 'original_device_class': , @@ -9295,6 +9467,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee', 'options': dict({ }), 'original_device_class': None, @@ -9366,6 +9539,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Current Mode', 'options': dict({ }), 'original_device_class': None, @@ -9418,6 +9592,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -9466,6 +9641,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -9513,6 +9689,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'My ecobee Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9602,6 +9779,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Fan', 'options': dict({ }), 'original_device_class': , @@ -9645,6 +9823,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Fan', 'options': dict({ }), 'original_device_class': , @@ -9688,6 +9867,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Fan Identify', 'options': dict({ }), 'original_device_class': , @@ -9733,6 +9913,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Fan Light Level', 'options': dict({ }), 'original_device_class': , @@ -9780,6 +9961,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Fan Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9828,6 +10010,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Fan', 'options': dict({ }), 'original_device_class': None, @@ -9911,6 +10094,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Identify', 'options': dict({ }), 'original_device_class': , @@ -9959,6 +10143,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Elevation', 'options': dict({ }), 'original_device_class': None, @@ -10010,6 +10195,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -10058,6 +10244,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Air Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10108,6 +10295,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Battery', 'options': dict({ }), 'original_device_class': , @@ -10156,6 +10344,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Humidity', 'options': dict({ }), 'original_device_class': , @@ -10203,6 +10392,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Degree AA11 Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -10292,6 +10482,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF Identify', 'options': dict({ }), 'original_device_class': , @@ -10337,6 +10528,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF Amps', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10387,6 +10579,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF Energy kWh', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10437,6 +10630,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10487,6 +10681,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF Volts', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10535,6 +10730,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF', 'options': dict({ }), 'original_device_class': None, @@ -10578,6 +10774,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Eve Energy 50FF Lock Physical Controls', 'options': dict({ }), 'original_device_class': None, @@ -10661,6 +10858,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HAA-C718B3 Identify', 'options': dict({ }), 'original_device_class': , @@ -10704,6 +10902,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HAA-C718B3 Setup', 'options': dict({ }), 'original_device_class': None, @@ -10746,6 +10945,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HAA-C718B3 Update', 'options': dict({ }), 'original_device_class': , @@ -10792,6 +10992,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HAA-C718B3', 'options': dict({ }), 'original_device_class': None, @@ -10881,6 +11082,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HAA-C718B3 Identify', 'options': dict({ }), 'original_device_class': , @@ -10924,6 +11126,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HAA-C718B3', 'options': dict({ }), 'original_device_class': None, @@ -11007,6 +11210,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Family Room North Identify', 'options': dict({ }), 'original_device_class': , @@ -11050,6 +11254,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Family Room North', 'options': dict({ }), 'original_device_class': None, @@ -11096,6 +11301,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Family Room North Battery', 'options': dict({ }), 'original_device_class': , @@ -11179,6 +11385,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -11259,6 +11466,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Window Identify', 'options': dict({ }), 'original_device_class': , @@ -11302,6 +11510,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Window', 'options': dict({ }), 'original_device_class': None, @@ -11348,6 +11557,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Window Battery', 'options': dict({ }), 'original_device_class': , @@ -11435,6 +11645,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Ceiling Fan Identify', 'options': dict({ }), 'original_device_class': , @@ -11481,6 +11692,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Ceiling Fan', 'options': dict({ }), 'original_device_class': None, @@ -11566,6 +11778,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Home Assistant Bridge Identify', 'options': dict({ }), 'original_device_class': , @@ -11646,6 +11859,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Fan Identify', 'options': dict({ }), 'original_device_class': , @@ -11692,6 +11906,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Fan', 'options': dict({ }), 'original_device_class': None, @@ -11782,6 +11997,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Identify', 'options': dict({ }), 'original_device_class': , @@ -11835,6 +12051,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room', 'options': dict({ }), 'original_device_class': None, @@ -11893,6 +12110,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room', 'options': dict({ }), 'original_device_class': None, @@ -11948,6 +12166,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -11996,6 +12215,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -12043,6 +12263,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -12128,6 +12349,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -12212,6 +12434,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -12292,6 +12515,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Laundry Smoke ED78 Identify', 'options': dict({ }), 'original_device_class': , @@ -12339,6 +12563,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Laundry Smoke ED78', 'options': dict({ }), 'original_device_class': None, @@ -12389,6 +12614,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Laundry Smoke ED78 Battery', 'options': dict({ }), 'original_device_class': , @@ -12476,6 +12702,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Family Room North Identify', 'options': dict({ }), 'original_device_class': , @@ -12519,6 +12746,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Family Room North', 'options': dict({ }), 'original_device_class': None, @@ -12565,6 +12793,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Family Room North Battery', 'options': dict({ }), 'original_device_class': , @@ -12648,6 +12877,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -12728,6 +12958,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Window Identify', 'options': dict({ }), 'original_device_class': , @@ -12771,6 +13002,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Window', 'options': dict({ }), 'original_device_class': None, @@ -12817,6 +13049,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Kitchen Window Battery', 'options': dict({ }), 'original_device_class': , @@ -12904,6 +13137,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Ceiling Fan Identify', 'options': dict({ }), 'original_device_class': , @@ -12950,6 +13184,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Ceiling Fan', 'options': dict({ }), 'original_device_class': None, @@ -13035,6 +13270,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Home Assistant Bridge Identify', 'options': dict({ }), 'original_device_class': , @@ -13115,6 +13351,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Fan Identify', 'options': dict({ }), 'original_device_class': , @@ -13161,6 +13398,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Fan', 'options': dict({ }), 'original_device_class': None, @@ -13252,6 +13490,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Home Assistant Bridge Identify', 'options': dict({ }), 'original_device_class': , @@ -13332,6 +13571,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Fan Identify', 'options': dict({ }), 'original_device_class': , @@ -13378,6 +13618,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Living Room Fan', 'options': dict({ }), 'original_device_class': None, @@ -13469,6 +13710,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Identify', 'options': dict({ }), 'original_device_class': , @@ -13526,6 +13768,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room', 'options': dict({ }), 'original_device_class': None, @@ -13589,6 +13832,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room', 'options': dict({ }), 'original_device_class': None, @@ -13644,6 +13888,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -13692,6 +13937,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -13739,6 +13985,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': '89 Living Room Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -13824,6 +14071,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -13908,6 +14156,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -13988,6 +14237,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Humidifier 182A Identify', 'options': dict({ }), 'original_device_class': , @@ -14038,6 +14288,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Humidifier 182A', 'options': dict({ }), 'original_device_class': , @@ -14093,6 +14344,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Humidifier 182A Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -14179,6 +14431,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -14259,6 +14512,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Humidifier 182A Identify', 'options': dict({ }), 'original_device_class': , @@ -14309,6 +14563,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Humidifier 182A', 'options': dict({ }), 'original_device_class': , @@ -14364,6 +14619,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Humidifier 182A Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -14450,6 +14706,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'HASS Bridge S6 Identify', 'options': dict({ }), 'original_device_class': , @@ -14530,6 +14787,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Laundry Smoke ED78 Identify', 'options': dict({ }), 'original_device_class': , @@ -14582,6 +14840,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Laundry Smoke ED78', 'options': dict({ }), 'original_device_class': None, @@ -14642,6 +14901,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Laundry Smoke ED78 Battery', 'options': dict({ }), 'original_device_class': , @@ -14729,6 +14989,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Air Conditioner Identify', 'options': dict({ }), 'original_device_class': , @@ -14788,6 +15049,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Air Conditioner SlaveID 1', 'options': dict({ }), 'original_device_class': None, @@ -14852,6 +15114,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Air Conditioner Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -14941,6 +15204,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle Identify', 'options': dict({ }), 'original_device_class': , @@ -14992,6 +15256,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle', 'options': dict({ }), 'original_device_class': None, @@ -15086,6 +15351,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle Identify', 'options': dict({ }), 'original_device_class': , @@ -15137,6 +15403,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle', 'options': dict({ }), 'original_device_class': None, @@ -15231,6 +15498,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle Identify', 'options': dict({ }), 'original_device_class': , @@ -15282,6 +15550,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle', 'options': dict({ }), 'original_device_class': None, @@ -15376,6 +15645,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle Identify', 'options': dict({ }), 'original_device_class': , @@ -15427,6 +15697,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance candle', 'options': dict({ }), 'original_device_class': None, @@ -15521,6 +15792,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance spot Identify', 'options': dict({ }), 'original_device_class': , @@ -15572,6 +15844,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance spot', 'options': dict({ }), 'original_device_class': None, @@ -15676,6 +15949,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance spot Identify', 'options': dict({ }), 'original_device_class': , @@ -15727,6 +16001,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue ambiance spot', 'options': dict({ }), 'original_device_class': None, @@ -15831,6 +16106,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue dimmer switch Identify', 'options': dict({ }), 'original_device_class': , @@ -15878,6 +16154,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue dimmer switch button 1', 'options': dict({ }), 'original_device_class': , @@ -15929,6 +16206,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue dimmer switch button 2', 'options': dict({ }), 'original_device_class': , @@ -15980,6 +16258,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue dimmer switch button 3', 'options': dict({ }), 'original_device_class': , @@ -16031,6 +16310,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue dimmer switch button 4', 'options': dict({ }), 'original_device_class': , @@ -16080,6 +16360,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue dimmer switch battery', 'options': dict({ }), 'original_device_class': , @@ -16163,6 +16444,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -16210,6 +16492,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -16295,6 +16578,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -16342,6 +16626,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -16427,6 +16712,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -16474,6 +16760,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -16559,6 +16846,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -16606,6 +16894,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -16691,6 +16980,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -16738,6 +17028,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -16823,6 +17114,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -16870,6 +17162,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -16955,6 +17248,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp Identify', 'options': dict({ }), 'original_device_class': , @@ -17002,6 +17296,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Hue white lamp', 'options': dict({ }), 'original_device_class': None, @@ -17087,6 +17382,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Philips hue - 482544 Identify', 'options': dict({ }), 'original_device_class': , @@ -17171,6 +17467,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-LS1-20833F Identify', 'options': dict({ }), 'original_device_class': , @@ -17223,6 +17520,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-LS1-20833F Light Strip', 'options': dict({ }), 'original_device_class': None, @@ -17322,6 +17620,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-P1-A00AA0 Identify', 'options': dict({ }), 'original_device_class': , @@ -17367,6 +17666,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-P1-A00AA0 Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17415,6 +17715,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-P1-A00AA0 outlet', 'options': dict({ }), 'original_device_class': None, @@ -17499,6 +17800,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-SW2-187A91 Identify', 'options': dict({ }), 'original_device_class': , @@ -17544,6 +17846,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-SW2-187A91 Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17592,6 +17895,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-SW2-187A91 Switch 1', 'options': dict({ }), 'original_device_class': None, @@ -17634,6 +17938,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Koogeek-SW2-187A91 Switch 2', 'options': dict({ }), 'original_device_class': None, @@ -17717,6 +18022,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lennox Identify', 'options': dict({ }), 'original_device_class': , @@ -17769,6 +18075,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lennox', 'options': dict({ }), 'original_device_class': None, @@ -17831,6 +18138,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lennox Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -17879,6 +18187,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lennox Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -17926,6 +18235,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Lennox Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -18015,6 +18325,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LG webOS TV AF80 Identify', 'options': dict({ }), 'original_device_class': , @@ -18068,6 +18379,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LG webOS TV AF80', 'options': dict({ }), 'original_device_class': , @@ -18122,6 +18434,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LG webOS TV AF80 Mute', 'options': dict({ }), 'original_device_class': None, @@ -18205,6 +18518,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Caséta® Wireless Fan Speed Control Identify', 'options': dict({ }), 'original_device_class': , @@ -18251,6 +18565,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Caséta® Wireless Fan Speed Control', 'options': dict({ }), 'original_device_class': None, @@ -18336,6 +18651,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Smart Bridge 2 Identify', 'options': dict({ }), 'original_device_class': , @@ -18420,6 +18736,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS425F-15cc Identify', 'options': dict({ }), 'original_device_class': , @@ -18463,6 +18780,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS425F-15cc Outlet-1', 'options': dict({ }), 'original_device_class': None, @@ -18505,6 +18823,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS425F-15cc Outlet-2', 'options': dict({ }), 'original_device_class': None, @@ -18547,6 +18866,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS425F-15cc Outlet-3', 'options': dict({ }), 'original_device_class': None, @@ -18589,6 +18909,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS425F-15cc Outlet-4', 'options': dict({ }), 'original_device_class': None, @@ -18631,6 +18952,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS425F-15cc USB', 'options': dict({ }), 'original_device_class': None, @@ -18714,6 +19036,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS565-28da Identify', 'options': dict({ }), 'original_device_class': , @@ -18761,6 +19084,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'MSS565-28da Dimmer Switch', 'options': dict({ }), 'original_device_class': None, @@ -18850,6 +19174,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mysa-85dda9 Identify', 'options': dict({ }), 'original_device_class': , @@ -18902,6 +19227,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mysa-85dda9 Thermostat', 'options': dict({ }), 'original_device_class': None, @@ -18961,6 +19287,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mysa-85dda9 Display', 'options': dict({ }), 'original_device_class': None, @@ -19014,6 +19341,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mysa-85dda9 Temperature Display Units', 'options': dict({ }), 'original_device_class': None, @@ -19062,6 +19390,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mysa-85dda9 Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -19109,6 +19438,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Mysa-85dda9 Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19198,6 +19528,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Nanoleaf Strip 3B32 Identify', 'options': dict({ }), 'original_device_class': , @@ -19250,6 +19581,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Nanoleaf Strip 3B32 Nanoleaf Light Strip', 'options': dict({ }), 'original_device_class': None, @@ -19327,6 +19659,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Nanoleaf Strip 3B32 Thread Capabilities', 'options': dict({ }), 'original_device_class': , @@ -19388,6 +19721,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Nanoleaf Strip 3B32 Thread Status', 'options': dict({ }), 'original_device_class': , @@ -19481,6 +19815,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Netatmo-Doorbell-g738658 Motion Sensor', 'options': dict({ }), 'original_device_class': , @@ -19524,6 +19859,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Netatmo-Doorbell-g738658 Identify', 'options': dict({ }), 'original_device_class': , @@ -19567,6 +19903,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Netatmo-Doorbell-g738658', 'options': dict({ }), 'original_device_class': None, @@ -19616,6 +19953,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Netatmo-Doorbell-g738658', 'options': dict({ }), 'original_device_class': , @@ -19665,6 +20003,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Netatmo-Doorbell-g738658 Mute', 'options': dict({ }), 'original_device_class': None, @@ -19707,6 +20046,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Netatmo-Doorbell-g738658 Mute', 'options': dict({ }), 'original_device_class': None, @@ -19790,6 +20130,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Smart CO Alarm Carbon Monoxide Sensor', 'options': dict({ }), 'original_device_class': , @@ -19833,6 +20174,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Smart CO Alarm Low Battery', 'options': dict({ }), 'original_device_class': , @@ -19876,6 +20218,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Smart CO Alarm Identify', 'options': dict({ }), 'original_device_class': , @@ -19960,6 +20303,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Healthy Home Coach Identify', 'options': dict({ }), 'original_device_class': , @@ -20005,6 +20349,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Healthy Home Coach Air Quality', 'options': dict({ }), 'original_device_class': , @@ -20051,6 +20396,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Healthy Home Coach Carbon Dioxide sensor', 'options': dict({ }), 'original_device_class': , @@ -20098,6 +20444,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Healthy Home Coach Humidity sensor', 'options': dict({ }), 'original_device_class': , @@ -20145,6 +20492,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Healthy Home Coach Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20195,6 +20543,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Healthy Home Coach Temperature sensor', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -20284,6 +20633,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a Identify', 'options': dict({ }), 'original_device_class': , @@ -20327,6 +20677,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20372,6 +20723,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20417,6 +20769,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20462,6 +20815,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20507,6 +20861,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20552,6 +20907,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20597,6 +20953,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20642,6 +20999,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RainMachine-00ce4a', 'options': dict({ }), 'original_device_class': None, @@ -20728,6 +21086,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Bath South Identify', 'options': dict({ }), 'original_device_class': , @@ -20771,6 +21130,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Bath South RYSE Shade', 'options': dict({ }), 'original_device_class': None, @@ -20817,6 +21177,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'Master Bath South RYSE Shade Battery', 'options': dict({ }), 'original_device_class': , @@ -20900,6 +21261,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RYSE SmartBridge Identify', 'options': dict({ }), 'original_device_class': , @@ -20980,6 +21342,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RYSE SmartShade Identify', 'options': dict({ }), 'original_device_class': , @@ -21023,6 +21386,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RYSE SmartShade RYSE Shade', 'options': dict({ }), 'original_device_class': None, @@ -21069,6 +21433,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RYSE SmartShade RYSE Shade Battery', 'options': dict({ }), 'original_device_class': , @@ -21156,6 +21521,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'BR Left Identify', 'options': dict({ }), 'original_device_class': , @@ -21199,6 +21565,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'BR Left RYSE Shade', 'options': dict({ }), 'original_device_class': None, @@ -21245,6 +21612,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'BR Left RYSE Shade Battery', 'options': dict({ }), 'original_device_class': , @@ -21328,6 +21696,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LR Left Identify', 'options': dict({ }), 'original_device_class': , @@ -21371,6 +21740,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LR Left RYSE Shade', 'options': dict({ }), 'original_device_class': None, @@ -21417,6 +21787,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LR Left RYSE Shade Battery', 'options': dict({ }), 'original_device_class': , @@ -21500,6 +21871,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LR Right Identify', 'options': dict({ }), 'original_device_class': , @@ -21543,6 +21915,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LR Right RYSE Shade', 'options': dict({ }), 'original_device_class': None, @@ -21589,6 +21962,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'LR Right RYSE Shade Battery', 'options': dict({ }), 'original_device_class': , @@ -21672,6 +22046,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RYSE SmartBridge Identify', 'options': dict({ }), 'original_device_class': , @@ -21752,6 +22127,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RZSS Identify', 'options': dict({ }), 'original_device_class': , @@ -21795,6 +22171,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RZSS RYSE Shade', 'options': dict({ }), 'original_device_class': None, @@ -21841,6 +22218,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'RZSS RYSE Shade Battery', 'options': dict({ }), 'original_device_class': , @@ -21928,6 +22306,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'SENSE Identify', 'options': dict({ }), 'original_device_class': , @@ -21971,6 +22350,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'SENSE Lock Mechanism', 'options': dict({ }), 'original_device_class': None, @@ -22055,6 +22435,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'SIMPLEconnect Fan-06F674 Identify', 'options': dict({ }), 'original_device_class': , @@ -22101,6 +22482,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'SIMPLEconnect Fan-06F674 Hunter Fan', 'options': dict({ }), 'original_device_class': None, @@ -22154,6 +22536,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'SIMPLEconnect Fan-06F674 Hunter Light', 'options': dict({ }), 'original_device_class': None, @@ -22243,6 +22626,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Internal Cover Identify', 'options': dict({ }), 'original_device_class': , @@ -22286,6 +22670,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Internal Cover Venetian Blinds', 'options': dict({ }), 'original_device_class': None, @@ -22372,6 +22757,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44 Identify', 'options': dict({ }), 'original_device_class': , @@ -22425,6 +22811,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44', 'options': dict({ }), 'original_device_class': None, @@ -22482,6 +22869,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44 Current Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22530,6 +22918,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44', 'options': dict({ }), 'original_device_class': None, @@ -22572,6 +22961,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44 Outlet 1', 'options': dict({ }), 'original_device_class': None, @@ -22615,6 +23005,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44 Outlet 2', 'options': dict({ }), 'original_device_class': None, @@ -22658,6 +23049,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44 Outlet 3', 'options': dict({ }), 'original_device_class': None, @@ -22701,6 +23093,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'U by Moen-015F44 Outlet 4', 'options': dict({ }), 'original_device_class': None, @@ -22785,6 +23178,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Identify', 'options': dict({ }), 'original_device_class': , @@ -22830,6 +23224,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Carbon Dioxide sensor', 'options': dict({ }), 'original_device_class': , @@ -22877,6 +23272,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Humidity sensor', 'options': dict({ }), 'original_device_class': , @@ -22924,6 +23320,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Temperature sensor', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -23013,6 +23410,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Gateway Identify', 'options': dict({ }), 'original_device_class': , @@ -23093,6 +23491,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Identify', 'options': dict({ }), 'original_device_class': , @@ -23138,6 +23537,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Carbon Dioxide sensor', 'options': dict({ }), 'original_device_class': , @@ -23185,6 +23585,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Humidity sensor', 'options': dict({ }), 'original_device_class': , @@ -23232,6 +23633,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Sensor Temperature sensor', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -23317,6 +23719,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Window Identify', 'options': dict({ }), 'original_device_class': , @@ -23360,6 +23763,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Window Roof Window', 'options': dict({ }), 'original_device_class': , @@ -23446,6 +23850,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Window Identify', 'options': dict({ }), 'original_device_class': , @@ -23489,6 +23894,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX Window Roof Window', 'options': dict({ }), 'original_device_class': , @@ -23575,6 +23981,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX External Cover Identify', 'options': dict({ }), 'original_device_class': , @@ -23618,6 +24025,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VELUX External Cover Awning Blinds', 'options': dict({ }), 'original_device_class': None, @@ -23703,6 +24111,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-Flowerbud-0d324b Identify', 'options': dict({ }), 'original_device_class': , @@ -23753,6 +24162,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-Flowerbud-0d324b', 'options': dict({ }), 'original_device_class': , @@ -23815,6 +24225,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-Flowerbud-0d324b Mood Light', 'options': dict({ }), 'original_device_class': None, @@ -23888,6 +24299,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-Flowerbud-0d324b Spray Quantity', 'options': dict({ }), 'original_device_class': None, @@ -23936,6 +24348,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-Flowerbud-0d324b Current Humidity', 'options': dict({ }), 'original_device_class': , @@ -24022,6 +24435,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-VP3-123456 Identify', 'options': dict({ }), 'original_device_class': , @@ -24067,6 +24481,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-VP3-123456 Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -24115,6 +24530,7 @@ 'labels': list([ ]), 'name': None, + 'object_id_base': 'VOCOlinc-VP3-123456 Outlet', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homekit_controller/test_device_trigger.py b/tests/components/homekit_controller/test_device_trigger.py index ba952ac5913..8e462a8600f 100644 --- a/tests/components/homekit_controller/test_device_trigger.py +++ b/tests/components/homekit_controller/test_device_trigger.py @@ -5,7 +5,6 @@ from collections.abc import Callable from aiohomekit.model import Accessory from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -import pytest from pytest_unordered import unordered from homeassistant.components import automation @@ -21,11 +20,6 @@ from .common import setup_test_component from tests.common import async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - def create_remote(accessory: Accessory) -> None: """Define characteristics for a button (that is inn a group).""" service_label = accessory.add_service(ServicesTypes.SERVICE_LABEL) diff --git a/tests/components/homewizard/snapshots/test_button.ambr b/tests/components/homewizard/snapshots/test_button.ambr index 967672580ec..037036a14aa 100644 --- a/tests/components/homewizard/snapshots/test_button.ambr +++ b/tests/components/homewizard/snapshots/test_button.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/homewizard/snapshots/test_number.ambr b/tests/components/homewizard/snapshots/test_number.ambr index 972b7fc5728..5ea8481e329 100644 --- a/tests/components/homewizard/snapshots/test_number.ambr +++ b/tests/components/homewizard/snapshots/test_number.ambr @@ -43,6 +43,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status light brightness', 'options': dict({ }), 'original_device_class': None, @@ -136,6 +137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status light brightness', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homewizard/snapshots/test_select.ambr b/tests/components/homewizard/snapshots/test_select.ambr index 10898ec527a..7e7d9afa95b 100644 --- a/tests/components/homewizard/snapshots/test_select.ambr +++ b/tests/components/homewizard/snapshots/test_select.ambr @@ -44,6 +44,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery group mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homewizard/snapshots/test_sensor.ambr b/tests/components/homewizard/snapshots/test_sensor.ambr index 75762620b04..19de085b8d2 100644 --- a/tests/components/homewizard/snapshots/test_sensor.ambr +++ b/tests/components/homewizard/snapshots/test_sensor.ambr @@ -57,6 +57,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery cycles', 'options': dict({ }), 'original_device_class': None, @@ -143,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -234,6 +236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -325,6 +328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -416,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -507,6 +512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -598,6 +604,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -689,6 +696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -778,6 +786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -864,6 +873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -955,6 +965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi RSSI', 'options': dict({ }), 'original_device_class': None, @@ -1040,6 +1051,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -1125,6 +1137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1216,6 +1229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1307,6 +1321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1398,6 +1413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1489,6 +1505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1580,6 +1597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1671,6 +1689,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -1759,6 +1778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1850,6 +1870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1941,6 +1962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2030,6 +2052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -2115,6 +2138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -2202,6 +2226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2293,6 +2318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2384,6 +2410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2475,6 +2502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2566,6 +2594,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2657,6 +2686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2748,6 +2778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2839,6 +2870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2930,6 +2962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3021,6 +3054,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3112,6 +3146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3203,6 +3238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3294,6 +3330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 1', 'options': dict({ }), 'original_device_class': , @@ -3382,6 +3419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 2', 'options': dict({ }), 'original_device_class': , @@ -3470,6 +3508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 3', 'options': dict({ }), 'original_device_class': , @@ -3558,6 +3597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3649,6 +3689,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3740,6 +3781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3831,6 +3873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3922,6 +3965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4013,6 +4057,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4104,6 +4149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4195,6 +4241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4286,6 +4333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4377,6 +4425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4468,6 +4517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4557,6 +4607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -4642,6 +4693,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -4727,6 +4779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average demand', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4817,6 +4870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4908,6 +4962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4999,6 +5054,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5088,6 +5144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSMR version', 'options': dict({ }), 'original_device_class': None, @@ -5173,6 +5230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5264,6 +5322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5355,6 +5414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5446,6 +5506,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5537,6 +5598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5628,6 +5690,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5719,6 +5782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5810,6 +5874,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5901,6 +5966,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5992,6 +6058,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6083,6 +6150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6172,6 +6240,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Long power failures detected', 'options': dict({ }), 'original_device_class': None, @@ -6255,6 +6324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak demand current month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6345,6 +6415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6434,6 +6505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power failures detected', 'options': dict({ }), 'original_device_class': None, @@ -6519,6 +6591,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6610,6 +6683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6701,6 +6775,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6790,6 +6865,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart meter identifier', 'options': dict({ }), 'original_device_class': None, @@ -6873,6 +6949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart meter model', 'options': dict({ }), 'original_device_class': None, @@ -6963,6 +7040,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tariff', 'options': dict({ }), 'original_device_class': , @@ -7055,6 +7133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total water usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7146,6 +7225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7237,6 +7317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7328,6 +7409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7417,6 +7499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 1', 'options': dict({ }), 'original_device_class': None, @@ -7500,6 +7583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 2', 'options': dict({ }), 'original_device_class': None, @@ -7583,6 +7667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 3', 'options': dict({ }), 'original_device_class': None, @@ -7666,6 +7751,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 1', 'options': dict({ }), 'original_device_class': None, @@ -7749,6 +7835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 2', 'options': dict({ }), 'original_device_class': None, @@ -7832,6 +7919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 3', 'options': dict({ }), 'original_device_class': None, @@ -7917,6 +8005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water usage', 'options': dict({ }), 'original_device_class': None, @@ -8002,6 +8091,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -8087,6 +8177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -8170,6 +8261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8257,6 +8349,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8290,7 +8383,7 @@ 'state': '444.444', }) # --- -# name: test_sensors[HWE-P1-entity_ids0][sensor.inlet_heat_meter_none:device-registry] +# name: test_sensors[HWE-P1-entity_ids0][sensor.inlet_heat_meter:device-registry] DeviceRegistryEntrySnapshot({ 'area_id': None, 'config_entries': , @@ -8321,7 +8414,7 @@ 'via_device_id': , }) # --- -# name: test_sensors[HWE-P1-entity_ids0][sensor.inlet_heat_meter_none:entity-registry] +# name: test_sensors[HWE-P1-entity_ids0][sensor.inlet_heat_meter:entity-registry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -8336,7 +8429,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.inlet_heat_meter_none', + 'entity_id': 'sensor.inlet_heat_meter', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -8344,6 +8437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -8358,7 +8452,7 @@ 'unit_of_measurement': , }) # --- -# name: test_sensors[HWE-P1-entity_ids0][sensor.inlet_heat_meter_none:state] +# name: test_sensors[HWE-P1-entity_ids0][sensor.inlet_heat_meter:state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'friendly_name': 'Inlet heat meter None', @@ -8366,7 +8460,7 @@ 'unit_of_measurement': , }), 'context': , - 'entity_id': 'sensor.inlet_heat_meter_none', + 'entity_id': 'sensor.inlet_heat_meter', 'last_changed': , 'last_reported': , 'last_updated': , @@ -8427,6 +8521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8514,6 +8609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8603,6 +8699,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average demand', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8693,6 +8790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8784,6 +8882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8875,6 +8974,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8964,6 +9064,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSMR version', 'options': dict({ }), 'original_device_class': None, @@ -9049,6 +9150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9140,6 +9242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9231,6 +9334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9322,6 +9426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9413,6 +9518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9504,6 +9610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9595,6 +9702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9686,6 +9794,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9777,6 +9886,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9868,6 +9978,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9959,6 +10070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10048,6 +10160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Long power failures detected', 'options': dict({ }), 'original_device_class': None, @@ -10131,6 +10244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak demand current month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10221,6 +10335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10310,6 +10425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power failures detected', 'options': dict({ }), 'original_device_class': None, @@ -10395,6 +10511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10486,6 +10603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10577,6 +10695,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10666,6 +10785,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart meter identifier', 'options': dict({ }), 'original_device_class': None, @@ -10749,6 +10869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart meter model', 'options': dict({ }), 'original_device_class': None, @@ -10839,6 +10960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tariff', 'options': dict({ }), 'original_device_class': , @@ -10931,6 +11053,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total water usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11022,6 +11145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11113,6 +11237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11204,6 +11329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11293,6 +11419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 1', 'options': dict({ }), 'original_device_class': None, @@ -11376,6 +11503,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 2', 'options': dict({ }), 'original_device_class': None, @@ -11459,6 +11587,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 3', 'options': dict({ }), 'original_device_class': None, @@ -11542,6 +11671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 1', 'options': dict({ }), 'original_device_class': None, @@ -11625,6 +11755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 2', 'options': dict({ }), 'original_device_class': None, @@ -11708,6 +11839,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 3', 'options': dict({ }), 'original_device_class': None, @@ -11793,6 +11925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water usage', 'options': dict({ }), 'original_device_class': None, @@ -11878,6 +12011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -11963,6 +12097,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -12046,6 +12181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12133,6 +12269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12166,7 +12303,7 @@ 'state': '444.444', }) # --- -# name: test_sensors[HWE-P1-invalid-EAN-entity_ids9][sensor.inlet_heat_meter_none:device-registry] +# name: test_sensors[HWE-P1-invalid-EAN-entity_ids9][sensor.inlet_heat_meter:device-registry] DeviceRegistryEntrySnapshot({ 'area_id': None, 'config_entries': , @@ -12197,7 +12334,7 @@ 'via_device_id': , }) # --- -# name: test_sensors[HWE-P1-invalid-EAN-entity_ids9][sensor.inlet_heat_meter_none:entity-registry] +# name: test_sensors[HWE-P1-invalid-EAN-entity_ids9][sensor.inlet_heat_meter:entity-registry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -12212,7 +12349,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.inlet_heat_meter_none', + 'entity_id': 'sensor.inlet_heat_meter', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -12220,6 +12357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -12234,7 +12372,7 @@ 'unit_of_measurement': , }) # --- -# name: test_sensors[HWE-P1-invalid-EAN-entity_ids9][sensor.inlet_heat_meter_none:state] +# name: test_sensors[HWE-P1-invalid-EAN-entity_ids9][sensor.inlet_heat_meter:state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'friendly_name': 'Inlet heat meter None', @@ -12242,7 +12380,7 @@ 'unit_of_measurement': , }), 'context': , - 'entity_id': 'sensor.inlet_heat_meter_none', + 'entity_id': 'sensor.inlet_heat_meter', 'last_changed': , 'last_reported': , 'last_updated': , @@ -12303,6 +12441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12390,6 +12529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12479,6 +12619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average demand', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12569,6 +12710,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12660,6 +12802,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12751,6 +12894,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12842,6 +12986,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12933,6 +13078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13024,6 +13170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13115,6 +13262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13206,6 +13354,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13297,6 +13446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13388,6 +13538,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13479,6 +13630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13570,6 +13722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13661,6 +13814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13752,6 +13906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13841,6 +13996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Long power failures detected', 'options': dict({ }), 'original_device_class': None, @@ -13926,6 +14082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14015,6 +14172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power failures detected', 'options': dict({ }), 'original_device_class': None, @@ -14100,6 +14258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14191,6 +14350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14282,6 +14442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14373,6 +14534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total water usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14464,6 +14626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14555,6 +14718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14646,6 +14810,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14735,6 +14900,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 1', 'options': dict({ }), 'original_device_class': None, @@ -14818,6 +14984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 2', 'options': dict({ }), 'original_device_class': None, @@ -14901,6 +15068,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage sags detected phase 3', 'options': dict({ }), 'original_device_class': None, @@ -14984,6 +15152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 1', 'options': dict({ }), 'original_device_class': None, @@ -15067,6 +15236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 2', 'options': dict({ }), 'original_device_class': None, @@ -15150,6 +15320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage swells detected phase 3', 'options': dict({ }), 'original_device_class': None, @@ -15235,6 +15406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water usage', 'options': dict({ }), 'original_device_class': None, @@ -15320,6 +15492,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -15405,6 +15578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -15492,6 +15666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15583,6 +15758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15674,6 +15850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15765,6 +15942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15856,6 +16034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15945,6 +16124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -16030,6 +16210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -16117,6 +16298,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16208,6 +16390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16299,6 +16482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16390,6 +16574,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16481,6 +16666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16572,6 +16758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16663,6 +16850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -16751,6 +16939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16842,6 +17031,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16933,6 +17123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17024,6 +17215,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17113,6 +17305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -17198,6 +17391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -17285,6 +17479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total water usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17376,6 +17571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water usage', 'options': dict({ }), 'original_device_class': None, @@ -17461,6 +17657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -17546,6 +17743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -17633,6 +17831,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17724,6 +17923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17815,6 +18015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17906,6 +18107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17997,6 +18199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18088,6 +18291,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18179,6 +18383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -18267,6 +18472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18358,6 +18564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18449,6 +18656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18538,6 +18746,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -18623,6 +18832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -18710,6 +18920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18801,6 +19012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18892,6 +19104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18983,6 +19196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -19074,6 +19288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -19165,6 +19380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -19256,6 +19472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -19347,6 +19564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -19438,6 +19656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -19529,6 +19748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -19620,6 +19840,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -19711,6 +19932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -19802,6 +20024,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 1', 'options': dict({ }), 'original_device_class': , @@ -19890,6 +20113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 2', 'options': dict({ }), 'original_device_class': , @@ -19978,6 +20202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor phase 3', 'options': dict({ }), 'original_device_class': , @@ -20066,6 +20291,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20157,6 +20383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20248,6 +20475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20339,6 +20567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20430,6 +20659,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20521,6 +20751,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20612,6 +20843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20703,6 +20935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reactive power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20794,6 +21027,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20885,6 +21119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -20976,6 +21211,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21065,6 +21301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi SSID', 'options': dict({ }), 'original_device_class': None, @@ -21150,6 +21387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homewizard/snapshots/test_switch.ambr b/tests/components/homewizard/snapshots/test_switch.ambr index d61979c84b5..e58b0d95550 100644 --- a/tests/components/homewizard/snapshots/test_switch.ambr +++ b/tests/components/homewizard/snapshots/test_switch.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +117,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, @@ -200,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -283,6 +286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, @@ -366,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch lock', 'options': dict({ }), 'original_device_class': None, @@ -450,6 +455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -533,6 +539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, @@ -616,6 +623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch lock', 'options': dict({ }), 'original_device_class': None, @@ -699,6 +707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, @@ -782,6 +791,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, @@ -865,6 +875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/homewizard/test_sensor.py b/tests/components/homewizard/test_sensor.py index 1f3d613ccd6..91a4a46b189 100644 --- a/tests/components/homewizard/test_sensor.py +++ b/tests/components/homewizard/test_sensor.py @@ -69,7 +69,7 @@ pytestmark = [ "sensor.device_wi_fi_strength", "sensor.gas_meter_gas", "sensor.heat_meter_energy", - "sensor.inlet_heat_meter_none", + "sensor.inlet_heat_meter", "sensor.warm_water_meter_water", "sensor.water_meter_water", ], @@ -296,7 +296,7 @@ pytestmark = [ "sensor.device_wi_fi_strength", "sensor.gas_meter_gas", "sensor.heat_meter_energy", - "sensor.inlet_heat_meter_none", + "sensor.inlet_heat_meter", "sensor.warm_water_meter_water", "sensor.water_meter_water", ], diff --git a/tests/components/hue_ble/snapshots/test_light.ambr b/tests/components/hue_ble/snapshots/test_light.ambr index 6a61270743e..a8bf82deba7 100644 --- a/tests/components/hue_ble/snapshots/test_light.ambr +++ b/tests/components/hue_ble/snapshots/test_light.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/humidifier/test_device_action.py b/tests/components/humidifier/test_device_action.py index 567be27721f..1d1f70574b0 100644 --- a/tests/components/humidifier/test_device_action.py +++ b/tests/components/humidifier/test_device_action.py @@ -24,11 +24,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_action_types"), [ diff --git a/tests/components/humidifier/test_device_condition.py b/tests/components/humidifier/test_device_condition.py index 55a2c687867..ef46f17a832 100644 --- a/tests/components/humidifier/test_device_condition.py +++ b/tests/components/humidifier/test_device_condition.py @@ -20,11 +20,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_condition_types"), [ diff --git a/tests/components/humidifier/test_device_trigger.py b/tests/components/humidifier/test_device_trigger.py index 6d45861b227..dfd6fc0bd10 100644 --- a/tests/components/humidifier/test_device_trigger.py +++ b/tests/components/humidifier/test_device_trigger.py @@ -33,11 +33,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/humidifier/test_trigger.py b/tests/components/humidifier/test_trigger.py index 1818da02ffc..d966304c876 100644 --- a/tests/components/humidifier/test_trigger.py +++ b/tests/components/humidifier/test_trigger.py @@ -1,8 +1,6 @@ """Test humidifier trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -15,7 +13,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, STATE_OFF, STATE_ from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_numerical_attribute_changed_trigger_states, parametrize_numerical_attribute_crossed_threshold_trigger_states, @@ -26,21 +24,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_humidifiers(hass: HomeAssistant) -> list[str]: """Create multiple humidifier entities associated with different targets.""" @@ -71,7 +54,7 @@ async def test_humidifier_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("humidifier"), @@ -100,7 +83,7 @@ async def test_humidifier_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the humidifier state trigger fires when any humidifier state changes to a specific state.""" other_entity_ids = set(target_humidifiers) - {entity_id} @@ -129,7 +112,7 @@ async def test_humidifier_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("humidifier"), @@ -166,7 +149,7 @@ async def test_humidifier_state_attribute_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the humidifier state trigger fires when any humidifier state changes to a specific state.""" other_entity_ids = set(target_humidifiers) - {entity_id} @@ -195,7 +178,7 @@ async def test_humidifier_state_attribute_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("humidifier"), @@ -224,7 +207,7 @@ async def test_humidifier_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the humidifier state trigger fires when the first humidifier changes to a specific state.""" other_entity_ids = set(target_humidifiers) - {entity_id} @@ -252,7 +235,7 @@ async def test_humidifier_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("humidifier"), @@ -316,7 +299,7 @@ async def test_humidifier_state_attribute_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("humidifier"), @@ -345,7 +328,7 @@ async def test_humidifier_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the humidifier state trigger fires when the last humidifier changes to a specific state.""" other_entity_ids = set(target_humidifiers) - {entity_id} @@ -372,7 +355,7 @@ async def test_humidifier_state_trigger_behavior_last( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("humidifier"), diff --git a/tests/components/husqvarna_automower/snapshots/test_binary_sensor.ambr b/tests/components/husqvarna_automower/snapshots/test_binary_sensor.ambr index 6c4e8e9e308..0f8a921571a 100644 --- a/tests/components/husqvarna_automower/snapshots/test_binary_sensor.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leaving dock', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leaving dock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/husqvarna_automower/snapshots/test_button.ambr b/tests/components/husqvarna_automower/snapshots/test_button.ambr index 058fc214a91..fe8476308e3 100644 --- a/tests/components/husqvarna_automower/snapshots/test_button.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Confirm error', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset cutting blade usage time', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync clock', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync clock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/husqvarna_automower/snapshots/test_device_tracker.ambr b/tests/components/husqvarna_automower/snapshots/test_device_tracker.ambr index acdf083f52c..2cf71f52d2a 100644 --- a/tests/components/husqvarna_automower/snapshots/test_device_tracker.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/husqvarna_automower/snapshots/test_event.ambr b/tests/components/husqvarna_automower/snapshots/test_event.ambr index e01f8d04f2c..8f819f5da37 100644 --- a/tests/components/husqvarna_automower/snapshots/test_event.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_event.ambr @@ -145,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Message', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/husqvarna_automower/snapshots/test_number.ambr b/tests/components/husqvarna_automower/snapshots/test_number.ambr index f0f45110b80..7501d054551 100644 --- a/tests/components/husqvarna_automower/snapshots/test_number.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Back lawn cutting height', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cutting height', 'options': dict({ }), 'original_device_class': None, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front lawn cutting height', 'options': dict({ }), 'original_device_class': None, @@ -198,6 +201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'My lawn cutting height', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/husqvarna_automower/snapshots/test_sensor.ambr b/tests/components/husqvarna_automower/snapshots/test_sensor.ambr index da9b1e86e85..54e761d087a 100644 --- a/tests/components/husqvarna_automower/snapshots/test_sensor.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cutting blade usage time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Downtime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -324,6 +327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': , @@ -505,6 +509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front lawn last time completed', 'options': dict({ }), 'original_device_class': , @@ -556,6 +561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front lawn progress', 'options': dict({ }), 'original_device_class': None, @@ -612,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inactive reason', 'options': dict({ }), 'original_device_class': , @@ -675,6 +682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': , @@ -732,6 +740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'My lawn last time completed', 'options': dict({ }), 'original_device_class': , @@ -783,6 +792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'My lawn progress', 'options': dict({ }), 'original_device_class': None, @@ -833,6 +843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next start', 'options': dict({ }), 'original_device_class': , @@ -884,6 +895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Number of charging cycles', 'options': dict({ }), 'original_device_class': None, @@ -935,6 +947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Number of collisions', 'options': dict({ }), 'original_device_class': None, @@ -984,6 +997,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1065,6 +1079,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restricted reason', 'options': dict({ }), 'original_device_class': , @@ -1140,6 +1155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1199,6 +1215,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cutting time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1258,6 +1275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total drive distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1317,6 +1335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total running time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1376,6 +1395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total searching time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1435,6 +1455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1499,6 +1520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Work area', 'options': dict({ }), 'original_device_class': , @@ -1561,6 +1583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1745,6 +1768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': , @@ -1935,6 +1959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': , @@ -1992,6 +2017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next start', 'options': dict({ }), 'original_device_class': , @@ -2041,6 +2067,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2122,6 +2149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restricted reason', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/husqvarna_automower/snapshots/test_switch.ambr b/tests/components/husqvarna_automower/snapshots/test_switch.ambr index a876fc4c1b6..9b3b91d10dc 100644 --- a/tests/components/husqvarna_automower/snapshots/test_switch.ambr +++ b/tests/components/husqvarna_automower/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avoid Danger Zone', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avoid Springflowers', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Back lawn', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Enable schedule', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front lawn', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'My lawn', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Enable schedule', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/husqvarna_automower_ble/snapshots/test_sensor.ambr b/tests/components/husqvarna_automower_ble/snapshots/test_sensor.ambr index 8f2bfadf56a..1bf9b6bbca7 100644 --- a/tests/components/husqvarna_automower_ble/snapshots/test_sensor.ambr +++ b/tests/components/husqvarna_automower_ble/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/huum/snapshots/test_binary_sensor.ambr b/tests/components/huum/snapshots/test_binary_sensor.ambr index 3490ff594b6..d1bfda5e732 100644 --- a/tests/components/huum/snapshots/test_binary_sensor.ambr +++ b/tests/components/huum/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/huum/snapshots/test_climate.ambr b/tests/components/huum/snapshots/test_climate.ambr index f18fd279f25..ab1aad4e5f6 100644 --- a/tests/components/huum/snapshots/test_climate.ambr +++ b/tests/components/huum/snapshots/test_climate.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/huum/snapshots/test_light.ambr b/tests/components/huum/snapshots/test_light.ambr index da449c16fe8..56c13b934b4 100644 --- a/tests/components/huum/snapshots/test_light.ambr +++ b/tests/components/huum/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/huum/snapshots/test_number.ambr b/tests/components/huum/snapshots/test_number.ambr index 19c0642f007..b87236f5ccc 100644 --- a/tests/components/huum/snapshots/test_number.ambr +++ b/tests/components/huum/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/hydrawise/snapshots/test_binary_sensor.ambr b/tests/components/hydrawise/snapshots/test_binary_sensor.ambr index 30adfea90be..f6fcd01393d 100644 --- a/tests/components/hydrawise/snapshots/test_binary_sensor.ambr +++ b/tests/components/hydrawise/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain sensor', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Watering', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Watering', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/hydrawise/snapshots/test_sensor.ambr b/tests/components/hydrawise/snapshots/test_sensor.ambr index 9a552db3984..ca9d3ab2b22 100644 --- a/tests/components/hydrawise/snapshots/test_sensor.ambr +++ b/tests/components/hydrawise/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily active water use', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily active watering time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily inactive water use', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -188,6 +191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily total water use', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -245,6 +249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily active water use', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily active watering time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -356,6 +362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next cycle', 'options': dict({ }), 'original_device_class': , @@ -406,6 +413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining watering time', 'options': dict({ }), 'original_device_class': None, @@ -456,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily active water use', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -514,6 +523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily active watering time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -568,6 +578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next cycle', 'options': dict({ }), 'original_device_class': , @@ -618,6 +629,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining watering time', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/hydrawise/snapshots/test_switch.ambr b/tests/components/hydrawise/snapshots/test_switch.ambr index 684e1d3ac3e..4fdb0ff3818 100644 --- a/tests/components/hydrawise/snapshots/test_switch.ambr +++ b/tests/components/hydrawise/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Automatic watering', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual watering', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Automatic watering', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual watering', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/hydrawise/snapshots/test_valve.ambr b/tests/components/hydrawise/snapshots/test_valve.ambr index 558c8f12a56..f42aa8f4eea 100644 --- a/tests/components/hydrawise/snapshots/test_valve.ambr +++ b/tests/components/hydrawise/snapshots/test_valve.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/icloud/test_config_flow.py b/tests/components/icloud/test_config_flow.py index 427fad63806..e7b901204f3 100644 --- a/tests/components/icloud/test_config_flow.py +++ b/tests/components/icloud/test_config_flow.py @@ -200,7 +200,7 @@ async def test_login_failed(hass: HomeAssistant) -> None: """Test when we have errors during login.""" with patch( "homeassistant.components.icloud.config_flow.PyiCloudService", - side_effect=PyiCloudFailedLoginException(), + side_effect=PyiCloudFailedLoginException(msg="Invalid login"), ): result = await hass.config_entries.flow.async_init( DOMAIN, @@ -410,7 +410,7 @@ async def test_password_update_wrong_password(hass: HomeAssistant) -> None: with patch( "homeassistant.components.icloud.config_flow.PyiCloudService", - side_effect=PyiCloudFailedLoginException(), + side_effect=PyiCloudFailedLoginException(msg="Invalid login"), ): result = await hass.config_entries.flow.async_configure( result["flow_id"], {CONF_PASSWORD: PASSWORD_2} diff --git a/tests/components/igloohome/snapshots/test_lock.ambr b/tests/components/igloohome/snapshots/test_lock.ambr index 1d539049411..f77906cef3b 100644 --- a/tests/components/igloohome/snapshots/test_lock.ambr +++ b/tests/components/igloohome/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/igloohome/snapshots/test_sensor.ambr b/tests/components/igloohome/snapshots/test_sensor.ambr index c2954ad5f15..978aed73135 100644 --- a/tests/components/igloohome/snapshots/test_sensor.ambr +++ b/tests/components/igloohome/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/imeon_inverter/snapshots/test_select.ambr b/tests/components/imeon_inverter/snapshots/test_select.ambr index 550402407ac..254b388f00c 100644 --- a/tests/components/imeon_inverter/snapshots/test_select.ambr +++ b/tests/components/imeon_inverter/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/imeon_inverter/snapshots/test_sensor.ambr b/tests/components/imeon_inverter/snapshots/test_sensor.ambr index 35b51043c73..394ab3d7c9d 100644 --- a/tests/components/imeon_inverter/snapshots/test_sensor.ambr +++ b/tests/components/imeon_inverter/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state of charge', 'options': dict({ }), 'original_device_class': , @@ -247,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery status', 'options': dict({ }), 'original_device_class': , @@ -303,6 +308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery stored', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -359,6 +365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Building consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -415,6 +422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging current limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -471,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Component temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -525,6 +534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Forecast remaining energy consumption for today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -578,6 +588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Forecast remaining energy production for today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -633,6 +644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -689,6 +701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid current L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -745,6 +758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid current L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -801,6 +815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid current L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -857,6 +872,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -913,6 +929,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid injection', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -969,6 +986,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid power flow', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1025,6 +1043,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid voltage L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1081,6 +1100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid voltage L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1137,6 +1157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid voltage L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1193,6 +1214,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Injection power limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1249,6 +1271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input power L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1305,6 +1328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input power L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1361,6 +1385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input power L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1417,6 +1442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input power total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1479,6 +1505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter state', 'options': dict({ }), 'original_device_class': , @@ -1537,6 +1564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1593,6 +1621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output current L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1649,6 +1678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output current L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1705,6 +1735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output current L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1761,6 +1792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1817,6 +1849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1873,6 +1906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1929,6 +1963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1985,6 +2020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2041,6 +2077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output voltage L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2097,6 +2134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output voltage L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2153,6 +2191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output voltage L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2209,6 +2248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2265,6 +2305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV injected', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2321,6 +2362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV power 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2377,6 +2419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV power 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2433,6 +2476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV power total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2489,6 +2533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2544,6 +2589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-sufficiency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2599,6 +2645,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2670,6 +2717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Timeline status', 'options': dict({ }), 'original_device_class': , @@ -2737,6 +2785,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Today battery-consumed energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2793,6 +2842,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Today battery-stored energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2849,6 +2899,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Today building consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2905,6 +2956,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Today grid-consumed energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2961,6 +3013,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Today grid-injected energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3017,6 +3070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Today PV energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/imeon_inverter/test_sensor.py b/tests/components/imeon_inverter/test_sensor.py index 9e69badea64..eca3bb3e2fa 100644 --- a/tests/components/imeon_inverter/test_sensor.py +++ b/tests/components/imeon_inverter/test_sensor.py @@ -38,7 +38,6 @@ async def test_sensors( ValueError, ], ) -@pytest.mark.asyncio async def test_sensor_unavailable_on_update_error( hass: HomeAssistant, mock_config_entry: MockConfigEntry, diff --git a/tests/components/imgw_pib/snapshots/test_sensor.ambr b/tests/components/imgw_pib/snapshots/test_sensor.ambr index cdefd949560..0eeadcf8845 100644 --- a/tests/components/imgw_pib/snapshots/test_sensor.ambr +++ b/tests/components/imgw_pib/snapshots/test_sensor.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hydrological alert', 'options': dict({ }), 'original_device_class': , @@ -89,6 +90,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water flow', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -146,6 +148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -203,6 +206,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/immich/snapshots/test_sensor.ambr b/tests/components/immich/snapshots/test_sensor.ambr index 590e7d9ad5c..9b2df54d7d8 100644 --- a/tests/components/immich/snapshots/test_sensor.ambr +++ b/tests/components/immich/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk available', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk usage', 'options': dict({ }), 'original_device_class': None, @@ -192,6 +195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -251,6 +255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used by photos', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -310,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used by videos', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -369,6 +375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Photos count', 'options': dict({ }), 'original_device_class': None, @@ -421,6 +428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Videos count', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/immich/snapshots/test_update.ambr b/tests/components/immich/snapshots/test_update.ambr index f3864511d13..80b435c09ba 100644 --- a/tests/components/immich/snapshots/test_update.ambr +++ b/tests/components/immich/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Version', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/incomfort/snapshots/test_binary_sensor.ambr b/tests/components/incomfort/snapshots/test_binary_sensor.ambr index cb938e5b1b7..31aefdacf71 100644 --- a/tests/components/incomfort/snapshots/test_binary_sensor.ambr +++ b/tests/components/incomfort/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault', 'options': dict({ }), 'original_device_class': , @@ -119,6 +121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water tap', 'options': dict({ }), 'original_device_class': , @@ -168,6 +171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , @@ -217,6 +221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner', 'options': dict({ }), 'original_device_class': , @@ -266,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault', 'options': dict({ }), 'original_device_class': , @@ -316,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water tap', 'options': dict({ }), 'original_device_class': , @@ -365,6 +372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , @@ -414,6 +422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner', 'options': dict({ }), 'original_device_class': , @@ -463,6 +472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault', 'options': dict({ }), 'original_device_class': , @@ -513,6 +523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water tap', 'options': dict({ }), 'original_device_class': , @@ -562,6 +573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , @@ -611,6 +623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner', 'options': dict({ }), 'original_device_class': , @@ -660,6 +673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault', 'options': dict({ }), 'original_device_class': , @@ -710,6 +724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water tap', 'options': dict({ }), 'original_device_class': , @@ -759,6 +774,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , @@ -808,6 +824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner', 'options': dict({ }), 'original_device_class': , @@ -857,6 +874,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault', 'options': dict({ }), 'original_device_class': , @@ -907,6 +925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water tap', 'options': dict({ }), 'original_device_class': , @@ -956,6 +975,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/incomfort/snapshots/test_climate.ambr b/tests/components/incomfort/snapshots/test_climate.ambr index dd5c9ca00d7..1f12f8d63e3 100644 --- a/tests/components/incomfort/snapshots/test_climate.ambr +++ b/tests/components/incomfort/snapshots/test_climate.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -94,6 +95,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -162,6 +164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -230,6 +233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/incomfort/snapshots/test_sensor.ambr b/tests/components/incomfort/snapshots/test_sensor.ambr index 07a5253028d..f0a927d99be 100644 --- a/tests/components/incomfort/snapshots/test_sensor.ambr +++ b/tests/components/incomfort/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RSSI', 'options': dict({ }), 'original_device_class': None, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tap temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/incomfort/snapshots/test_water_heater.ambr b/tests/components/incomfort/snapshots/test_water_heater.ambr index dd55793290f..db8bba74164 100644 --- a/tests/components/incomfort/snapshots/test_water_heater.ambr +++ b/tests/components/incomfort/snapshots/test_water_heater.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/intellifire/snapshots/test_binary_sensor.ambr b/tests/components/intellifire/snapshots/test_binary_sensor.ambr index 2c33012488b..03adc97aa2e 100644 --- a/tests/components/intellifire/snapshots/test_binary_sensor.ambr +++ b/tests/components/intellifire/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Accessory error', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connectivity', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disabled error', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ECM offline error', 'options': dict({ }), 'original_device_class': , @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan delay error', 'options': dict({ }), 'original_device_class': , @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan error', 'options': dict({ }), 'original_device_class': , @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flame', 'options': dict({ }), 'original_device_class': None, @@ -369,6 +376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flame error', 'options': dict({ }), 'original_device_class': , @@ -419,6 +427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lights error', 'options': dict({ }), 'original_device_class': , @@ -469,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local connectivity', 'options': dict({ }), 'original_device_class': , @@ -519,6 +529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maintenance error', 'options': dict({ }), 'original_device_class': , @@ -569,6 +580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Offline error', 'options': dict({ }), 'original_device_class': , @@ -619,6 +631,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pilot flame error', 'options': dict({ }), 'original_device_class': , @@ -669,6 +682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pilot light on', 'options': dict({ }), 'original_device_class': None, @@ -718,6 +732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soft lock out error', 'options': dict({ }), 'original_device_class': , @@ -768,6 +783,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat on', 'options': dict({ }), 'original_device_class': None, @@ -817,6 +833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Timer on', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/intellifire/snapshots/test_climate.ambr b/tests/components/intellifire/snapshots/test_climate.ambr index e13d9c6c0b4..d82630a22bf 100644 --- a/tests/components/intellifire/snapshots/test_climate.ambr +++ b/tests/components/intellifire/snapshots/test_climate.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/intellifire/snapshots/test_sensor.ambr b/tests/components/intellifire/snapshots/test_sensor.ambr index a641db96ffc..6ec468ef141 100644 --- a/tests/components/intellifire/snapshots/test_sensor.ambr +++ b/tests/components/intellifire/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection quality', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Downtime', 'options': dict({ }), 'original_device_class': , @@ -119,6 +121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ECM latency', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan speed', 'options': dict({ }), 'original_device_class': None, @@ -222,6 +226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flame height', 'options': dict({ }), 'original_device_class': None, @@ -272,6 +277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IP address', 'options': dict({ }), 'original_device_class': None, @@ -323,6 +329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -380,6 +387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -437,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Timer end', 'options': dict({ }), 'original_device_class': , @@ -488,6 +497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/iometer/snapshots/test_binary_sensor.ambr b/tests/components/iometer/snapshots/test_binary_sensor.ambr index 7e64f56a1fc..73f3c7b60b0 100644 --- a/tests/components/iometer/snapshots/test_binary_sensor.ambr +++ b/tests/components/iometer/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core attachment status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core/Bridge connection status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/iotty/snapshots/test_switch.ambr b/tests/components/iotty/snapshots/test_switch.ambr index 41e79911154..f0d3a5f32d8 100644 --- a/tests/components/iotty/snapshots/test_switch.ambr +++ b/tests/components/iotty/snapshots/test_switch.ambr @@ -69,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/ipp/snapshots/test_sensor.ambr b/tests/components/ipp/snapshots/test_sensor.ambr index 5a9669c1afb..a7ed94c4ecd 100644 --- a/tests/components/ipp/snapshots/test_sensor.ambr +++ b/tests/components/ipp/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -89,6 +90,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Black ink', 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cyan ink', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Magenta ink', 'options': dict({ }), 'original_device_class': None, @@ -254,6 +258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Photo black ink', 'options': dict({ }), 'original_device_class': None, @@ -307,6 +312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yellow ink', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/irm_kmi/snapshots/test_weather.ambr b/tests/components/irm_kmi/snapshots/test_weather.ambr index a8a0c92b539..528dd0848f9 100644 --- a/tests/components/irm_kmi/snapshots/test_weather.ambr +++ b/tests/components/irm_kmi/snapshots/test_weather.ambr @@ -653,6 +653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/iron_os/snapshots/test_binary_sensor.ambr b/tests/components/iron_os/snapshots/test_binary_sensor.ambr index 5d866d38786..d23933415b3 100644 --- a/tests/components/iron_os/snapshots/test_binary_sensor.ambr +++ b/tests/components/iron_os/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soldering tip', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/iron_os/snapshots/test_button.ambr b/tests/components/iron_os/snapshots/test_button.ambr index 329940d5ca1..697b95007ba 100644 --- a/tests/components/iron_os/snapshots/test_button.ambr +++ b/tests/components/iron_os/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restore default settings', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Save settings', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/iron_os/snapshots/test_number.ambr b/tests/components/iron_os/snapshots/test_number.ambr index 377d29f4a71..6ce5ee75463 100644 --- a/tests/components/iron_os/snapshots/test_number.ambr +++ b/tests/components/iron_os/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boost temperature', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibration offset', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display brightness', 'options': dict({ }), 'original_device_class': None, @@ -198,6 +201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hall effect sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -255,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hall sensor sleep timeout', 'options': dict({ }), 'original_device_class': None, @@ -313,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keep-awake pulse delay', 'options': dict({ }), 'original_device_class': None, @@ -371,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keep-awake pulse duration', 'options': dict({ }), 'original_device_class': None, @@ -429,6 +436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keep-awake pulse intensity', 'options': dict({ }), 'original_device_class': None, @@ -487,6 +495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Long-press temperature step', 'options': dict({ }), 'original_device_class': None, @@ -545,6 +554,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Min. voltage per cell', 'options': dict({ }), 'original_device_class': None, @@ -603,6 +613,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -660,6 +671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power Delivery timeout', 'options': dict({ }), 'original_device_class': , @@ -719,6 +731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power limit', 'options': dict({ }), 'original_device_class': None, @@ -777,6 +790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Quick Charge voltage', 'options': dict({ }), 'original_device_class': , @@ -836,6 +850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint temperature', 'options': dict({ }), 'original_device_class': None, @@ -894,6 +909,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Short-press temperature step', 'options': dict({ }), 'original_device_class': None, @@ -952,6 +968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Shutdown timeout', 'options': dict({ }), 'original_device_class': , @@ -1011,6 +1028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep temperature', 'options': dict({ }), 'original_device_class': None, @@ -1069,6 +1087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep timeout', 'options': dict({ }), 'original_device_class': None, @@ -1127,6 +1146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage divider', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/iron_os/snapshots/test_select.ambr b/tests/components/iron_os/snapshots/test_select.ambr index 41696371411..02e54addcf7 100644 --- a/tests/components/iron_os/snapshots/test_select.ambr +++ b/tests/components/iron_os/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Animation speed', 'options': dict({ }), 'original_device_class': None, @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boot logo duration', 'options': dict({ }), 'original_device_class': None, @@ -154,6 +156,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button locking mode', 'options': dict({ }), 'original_device_class': None, @@ -213,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display orientation mode', 'options': dict({ }), 'original_device_class': None, @@ -272,6 +276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power Delivery 3.1 EPR', 'options': dict({ }), 'original_device_class': None, @@ -333,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power source', 'options': dict({ }), 'original_device_class': None, @@ -393,6 +399,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scrolling speed', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soldering tip type', 'options': dict({ }), 'original_device_class': None, @@ -513,6 +521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start-up behavior', 'options': dict({ }), 'original_device_class': None, @@ -572,6 +581,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature display unit', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/iron_os/snapshots/test_sensor.ambr b/tests/components/iron_os/snapshots/test_sensor.ambr index caab12d4120..6fa8667faee 100644 --- a/tests/components/iron_os/snapshots/test_sensor.ambr +++ b/tests/components/iron_os/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DC input voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hall effect strength', 'options': dict({ }), 'original_device_class': None, @@ -185,6 +188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Handle temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -241,6 +245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last movement time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -295,6 +300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max tip temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -366,6 +372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating mode', 'options': dict({ }), 'original_device_class': , @@ -434,6 +441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -495,6 +503,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power source', 'options': dict({ }), 'original_device_class': , @@ -552,6 +561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw tip voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -608,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tip resistance', 'options': dict({ }), 'original_device_class': None, @@ -660,6 +671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tip temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -716,6 +728,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/iron_os/snapshots/test_switch.ambr b/tests/components/iron_os/snapshots/test_switch.ambr index a0591c88fdf..47df9a8c5ff 100644 --- a/tests/components/iron_os/snapshots/test_switch.ambr +++ b/tests/components/iron_os/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Animation loop', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boost', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibrate CJC', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cool down screen flashing', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Detailed idle screen', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Detailed solder screen', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Invert screen', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Swap +/- buttons', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/iron_os/snapshots/test_update.ambr b/tests/components/iron_os/snapshots/test_update.ambr index 48d702001a4..64c4e692071 100644 --- a/tests/components/iron_os/snapshots/test_update.ambr +++ b/tests/components/iron_os/snapshots/test_update.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/israel_rail/snapshots/test_sensor.ambr b/tests/components/israel_rail/snapshots/test_sensor.ambr index e9c9bec80aa..145cfb53179 100644 --- a/tests/components/israel_rail/snapshots/test_sensor.ambr +++ b/tests/components/israel_rail/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure +1', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure +2', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Platform', 'options': dict({ }), 'original_device_class': None, @@ -219,6 +223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Train number', 'options': dict({ }), 'original_device_class': None, @@ -268,6 +273,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trains', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ista_ecotrend/snapshots/test_sensor.ambr b/tests/components/ista_ecotrend/snapshots/test_sensor.ambr index 1d6cabcd2fa..c6754b415c1 100644 --- a/tests/components/ista_ecotrend/snapshots/test_sensor.ambr +++ b/tests/components/ista_ecotrend/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating cost', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -133,6 +135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -189,6 +192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -245,6 +249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water cost', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -301,6 +306,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -357,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -413,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water cost', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -469,6 +477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -524,6 +533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating cost', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -580,6 +590,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -636,6 +647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -692,6 +704,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water cost', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -748,6 +761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -804,6 +818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -860,6 +875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water cost', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/ituran/snapshots/test_binary_sensor.ambr b/tests/components/ituran/snapshots/test_binary_sensor.ambr index fed9f2b487c..224e39866da 100644 --- a/tests/components/ituran/snapshots/test_binary_sensor.ambr +++ b/tests/components/ituran/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/ituran/snapshots/test_device_tracker.ambr b/tests/components/ituran/snapshots/test_device_tracker.ambr index 2bd5286f7e4..86942500856 100644 --- a/tests/components/ituran/snapshots/test_device_tracker.ambr +++ b/tests/components/ituran/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ituran/snapshots/test_sensor.ambr b/tests/components/ituran/snapshots/test_sensor.ambr index a577d836b0e..64b48d7fcbb 100644 --- a/tests/components/ituran/snapshots/test_sensor.ambr +++ b/tests/components/ituran/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Address', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -171,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heading', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -223,6 +227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last update from vehicle', 'options': dict({ }), 'original_device_class': , @@ -272,6 +277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -325,6 +331,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -378,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -431,6 +439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Address', 'options': dict({ }), 'original_device_class': None, @@ -479,6 +488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -532,6 +542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heading', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -584,6 +595,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last update from vehicle', 'options': dict({ }), 'original_device_class': , @@ -633,6 +645,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -686,6 +699,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/jvc_projector/__init__.py b/tests/components/jvc_projector/__init__.py index d8554e8f4cd..d96e004114c 100644 --- a/tests/components/jvc_projector/__init__.py +++ b/tests/components/jvc_projector/__init__.py @@ -3,5 +3,6 @@ MOCK_HOST = "127.0.0.1" MOCK_PORT = 20554 MOCK_PASSWORD = "jvcpasswd" -MOCK_MAC = "jvcmac" -MOCK_MODEL = "jvcmodel" +MOCK_MAC = "E0DADC0A1234" +MOCK_MAC_FORMATED = "e0:da:dc:0a:12:34" +MOCK_MODEL = "B2A2" diff --git a/tests/components/jvc_projector/conftest.py b/tests/components/jvc_projector/conftest.py index 3115cbfe252..57603e0a055 100644 --- a/tests/components/jvc_projector/conftest.py +++ b/tests/components/jvc_projector/conftest.py @@ -3,11 +3,13 @@ from collections.abc import Generator from unittest.mock import MagicMock, patch +from jvcprojector import command as cmd import pytest from homeassistant.components.jvc_projector.const import DOMAIN from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import format_mac from . import MOCK_HOST, MOCK_MAC, MOCK_MODEL, MOCK_PASSWORD, MOCK_PORT @@ -20,16 +22,31 @@ def fixture_mock_device( ) -> Generator[MagicMock]: """Return a mocked JVC Projector device.""" target = "homeassistant.components.jvc_projector.JvcProjector" + fixture: dict[str, str] = { + "mac": MOCK_MAC, + "power": "standby", + "input": "hdmi-1", + } + if hasattr(request, "param"): - target = request.param + target = request.param.get("target", target) + fixture = request.param.get("get", fixture) + + async def device_get(command) -> str: + if command is cmd.MacAddress: + return fixture["mac"] + if command is cmd.Power: + return fixture["power"] + if command is cmd.Input: + return fixture["input"] + raise ValueError(f"Fixture failure; unexpected command {command}") with patch(target, autospec=True) as mock: device = mock.return_value device.host = MOCK_HOST device.port = MOCK_PORT - device.mac = MOCK_MAC device.model = MOCK_MODEL - device.get_state.return_value = {"power": "standby", "input": "hdmi1"} + device.get.side_effect = device_get yield device @@ -38,7 +55,7 @@ def fixture_mock_config_entry() -> MockConfigEntry: """Return a mock config entry.""" return MockConfigEntry( domain=DOMAIN, - unique_id=MOCK_MAC, + unique_id=format_mac(MOCK_MAC), version=1, data={ CONF_HOST: MOCK_HOST, diff --git a/tests/components/jvc_projector/test_binary_sensor.py b/tests/components/jvc_projector/test_binary_sensor.py index b327538991c..e7884c9c784 100644 --- a/tests/components/jvc_projector/test_binary_sensor.py +++ b/tests/components/jvc_projector/test_binary_sensor.py @@ -2,9 +2,13 @@ from unittest.mock import MagicMock +from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN +from homeassistant.components.jvc_projector.const import DOMAIN from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from . import MOCK_MAC, MOCK_MAC_FORMATED + from tests.common import MockConfigEntry ENTITY_ID = "binary_sensor.jvc_projector_power" @@ -20,3 +24,40 @@ async def test_entity_state( entity = hass.states.get(ENTITY_ID) assert entity assert entity_registry.async_get(entity.entity_id) + + +async def test_migrate_old_unique_id( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_device: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Tests power binary sensor unique id is reformatted.""" + mock_config_entry.add_to_hass(hass) + + # Entity to be migrated + entity_registry.async_get_or_create( + BINARY_SENSOR_DOMAIN, + DOMAIN, + f"{MOCK_MAC}_power", + config_entry=mock_config_entry, + suggested_object_id="jvc_projector_power", + ) + + # Ignored entity to get to 100% coverage + entity_registry.async_get_or_create( + BINARY_SENSOR_DOMAIN, + DOMAIN, + f"{MOCK_MAC}_ignore", + config_entry=mock_config_entry, + suggested_object_id="jvc_projector_ignore", + ) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + entity = hass.states.get(ENTITY_ID) + assert entity + entry = entity_registry.async_get(entity.entity_id) + assert entry + assert entry.unique_id == f"{MOCK_MAC_FORMATED}_power" diff --git a/tests/components/jvc_projector/test_config_flow.py b/tests/components/jvc_projector/test_config_flow.py index d7eb0995bbd..d1d4287ab04 100644 --- a/tests/components/jvc_projector/test_config_flow.py +++ b/tests/components/jvc_projector/test_config_flow.py @@ -2,7 +2,7 @@ from unittest.mock import AsyncMock -from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector import JvcProjectorAuthError, JvcProjectorTimeoutError import pytest from homeassistant.components.jvc_projector.const import DOMAIN @@ -18,7 +18,7 @@ from tests.common import MockConfigEntry TARGET = "homeassistant.components.jvc_projector.config_flow.JvcProjector" -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_user_config_flow_success( hass: HomeAssistant, mock_device: AsyncMock ) -> None: @@ -46,12 +46,12 @@ async def test_user_config_flow_success( assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_user_config_flow_bad_connect_errors( hass: HomeAssistant, mock_device: AsyncMock ) -> None: """Test errors when connection error occurs.""" - mock_device.connect.side_effect = JvcProjectorConnectError + mock_device.connect.side_effect = JvcProjectorTimeoutError result = await hass.config_entries.flow.async_init( DOMAIN, @@ -80,7 +80,7 @@ async def test_user_config_flow_bad_connect_errors( assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_user_config_flow_device_exists_abort( hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry ) -> None: @@ -94,7 +94,7 @@ async def test_user_config_flow_device_exists_abort( assert result["reason"] == "already_configured" -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_user_config_flow_bad_host_errors( hass: HomeAssistant, mock_device: AsyncMock ) -> None: @@ -124,7 +124,7 @@ async def test_user_config_flow_bad_host_errors( assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_user_config_flow_bad_auth_errors( hass: HomeAssistant, mock_device: AsyncMock ) -> None: @@ -158,7 +158,7 @@ async def test_user_config_flow_bad_auth_errors( assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_reauth_config_flow_success( hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry ) -> None: @@ -180,7 +180,7 @@ async def test_reauth_config_flow_success( assert mock_integration.data[CONF_PASSWORD] == MOCK_PASSWORD -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_reauth_config_flow_auth_error( hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry ) -> None: @@ -221,12 +221,12 @@ async def test_reauth_config_flow_auth_error( assert mock_integration.data[CONF_PASSWORD] == MOCK_PASSWORD -@pytest.mark.parametrize("mock_device", [TARGET], indirect=True) +@pytest.mark.parametrize("mock_device", [{"target": TARGET}], indirect=True) async def test_reauth_config_flow_connect_error( hass: HomeAssistant, mock_device: AsyncMock, mock_integration: MockConfigEntry ) -> None: """Test reauth config flow when connect fails.""" - mock_device.connect.side_effect = JvcProjectorConnectError + mock_device.connect.side_effect = JvcProjectorTimeoutError result = await mock_integration.start_reauth_flow(hass) assert result["type"] is FlowResultType.FORM diff --git a/tests/components/jvc_projector/test_coordinator.py b/tests/components/jvc_projector/test_coordinator.py index b9211250aff..569e894044d 100644 --- a/tests/components/jvc_projector/test_coordinator.py +++ b/tests/components/jvc_projector/test_coordinator.py @@ -3,7 +3,8 @@ from datetime import timedelta from unittest.mock import AsyncMock -from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector import JvcProjectorAuthError, JvcProjectorTimeoutError +import pytest from homeassistant.components.jvc_projector.coordinator import ( INTERVAL_FAST, @@ -13,6 +14,8 @@ from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.util.dt import utcnow +from . import MOCK_MAC + from tests.common import MockConfigEntry, async_fire_time_changed @@ -22,49 +25,51 @@ async def test_coordinator_update( mock_integration: MockConfigEntry, ) -> None: """Test coordinator update runs.""" - mock_device.get_state.return_value = {"power": "standby", "input": "hdmi1"} async_fire_time_changed( hass, utcnow() + timedelta(seconds=INTERVAL_SLOW.seconds + 1) ) await hass.async_block_till_done() - assert mock_device.get_state.call_count == 3 coordinator = mock_integration.runtime_data assert coordinator.update_interval == INTERVAL_SLOW -async def test_coordinator_connect_error( +async def test_coordinator_setup_connect_error( hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry, ) -> None: """Test coordinator connect error.""" - mock_device.get_state.side_effect = JvcProjectorConnectError + mock_device.get.side_effect = JvcProjectorTimeoutError mock_config_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY -async def test_coordinator_auth_error( +async def test_coordinator_setup_auth_error( hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry, ) -> None: """Test coordinator auth error.""" - mock_device.get_state.side_effect = JvcProjectorAuthError + mock_device.get.side_effect = JvcProjectorAuthError mock_config_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR +@pytest.mark.parametrize( + "mock_device", + [{"get": {"mac": MOCK_MAC, "power": "on", "input": "hdmi-1"}}], + indirect=True, +) async def test_coordinator_device_on( hass: HomeAssistant, mock_device: AsyncMock, mock_config_entry: MockConfigEntry, ) -> None: """Test coordinator changes update interval when device is on.""" - mock_device.get_state.return_value = {"power": "on", "input": "hdmi1"} mock_config_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() diff --git a/tests/components/jvc_projector/test_init.py b/tests/components/jvc_projector/test_init.py index baf088a5dba..93819680845 100644 --- a/tests/components/jvc_projector/test_init.py +++ b/tests/components/jvc_projector/test_init.py @@ -2,12 +2,14 @@ from unittest.mock import AsyncMock -from jvcprojector import JvcProjectorAuthError, JvcProjectorConnectError +from jvcprojector import JvcProjectorAuthError, JvcProjectorTimeoutError from homeassistant.components.jvc_projector.const import DOMAIN from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr +from homeassistant.helpers.device_registry import format_mac from . import MOCK_MAC @@ -21,9 +23,10 @@ async def test_init( mock_integration: MockConfigEntry, ) -> None: """Test initialization.""" - device = device_registry.async_get_device(identifiers={(DOMAIN, MOCK_MAC)}) + mac = format_mac(MOCK_MAC) + device = device_registry.async_get_device(identifiers={(DOMAIN, mac)}) assert device is not None - assert device.identifiers == {(DOMAIN, MOCK_MAC)} + assert device.identifiers == {(DOMAIN, mac)} async def test_unload_config_entry( @@ -38,6 +41,23 @@ async def test_unload_config_entry( await hass.config_entries.async_unload(mock_config_entry.entry_id) await hass.async_block_till_done() + assert mock_device.disconnect.call_count == 1 + + +async def test_disconnect_on_hass_stop( + hass: HomeAssistant, + mock_device: AsyncMock, + mock_integration: MockConfigEntry, +) -> None: + """Test device disconnects when Home Assistant stops.""" + assert mock_integration.state is ConfigEntryState.LOADED + assert mock_device.disconnect.call_count == 0 + + hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) + await hass.async_block_till_done() + + assert mock_device.disconnect.call_count == 1 + async def test_config_entry_connect_error( hass: HomeAssistant, @@ -45,7 +65,7 @@ async def test_config_entry_connect_error( mock_config_entry: MockConfigEntry, ) -> None: """Test config entry with connect error.""" - mock_device.connect.side_effect = JvcProjectorConnectError + mock_device.connect.side_effect = JvcProjectorTimeoutError mock_config_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_config_entry.entry_id) diff --git a/tests/components/jvc_projector/test_remote.py b/tests/components/jvc_projector/test_remote.py index 28bf835e032..56e929d4898 100644 --- a/tests/components/jvc_projector/test_remote.py +++ b/tests/components/jvc_projector/test_remote.py @@ -43,7 +43,7 @@ async def test_commands( {ATTR_ENTITY_ID: ENTITY_ID}, blocking=True, ) - assert mock_device.power_on.call_count == 1 + assert mock_device.get.call_count == 3 await hass.services.async_call( REMOTE_DOMAIN, @@ -51,7 +51,7 @@ async def test_commands( {ATTR_ENTITY_ID: ENTITY_ID}, blocking=True, ) - assert mock_device.power_off.call_count == 1 + assert mock_device.get.call_count == 4 await hass.services.async_call( REMOTE_DOMAIN, @@ -64,11 +64,27 @@ async def test_commands( await hass.services.async_call( REMOTE_DOMAIN, SERVICE_SEND_COMMAND, - {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["hdmi_1"]}, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["hdmi1"]}, blocking=True, ) assert mock_device.remote.call_count == 2 + await hass.services.async_call( + REMOTE_DOMAIN, + SERVICE_SEND_COMMAND, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["anamo"]}, + blocking=True, + ) + assert mock_device.remote.call_count == 3 + + await hass.services.async_call( + REMOTE_DOMAIN, + SERVICE_SEND_COMMAND, + {ATTR_ENTITY_ID: ENTITY_ID, ATTR_COMMAND: ["picture_mode"]}, + blocking=True, + ) + assert mock_device.remote.call_count == 4 + async def test_unknown_command( hass: HomeAssistant, diff --git a/tests/components/jvc_projector/test_select.py b/tests/components/jvc_projector/test_select.py index a52133bd688..5e8bed6eec7 100644 --- a/tests/components/jvc_projector/test_select.py +++ b/tests/components/jvc_projector/test_select.py @@ -2,7 +2,8 @@ from unittest.mock import MagicMock -from jvcprojector import const +from jvcprojector import command as cmd +import pytest from homeassistant.components.select import ( ATTR_OPTIONS, @@ -13,11 +14,18 @@ from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_OPTION from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from . import MOCK_MAC + from tests.common import MockConfigEntry INPUT_ENTITY_ID = "select.jvc_projector_input" +@pytest.mark.parametrize( + "mock_device", + [{"get": {"mac": MOCK_MAC, "power": "on", "input": "hdmi-1"}}], + indirect=True, +) async def test_input_select( hass: HomeAssistant, entity_registry: er.EntityRegistry, @@ -28,17 +36,15 @@ async def test_input_select( entity = hass.states.get(INPUT_ENTITY_ID) assert entity assert entity.attributes.get(ATTR_FRIENDLY_NAME) == "JVC Projector Input" - assert entity.attributes.get(ATTR_OPTIONS) == [const.HDMI1, const.HDMI2] - assert entity.state == const.HDMI1 + assert entity.attributes.get(ATTR_OPTIONS) == [cmd.Input.HDMI1, cmd.Input.HDMI2] await hass.services.async_call( SELECT_DOMAIN, SERVICE_SELECT_OPTION, { ATTR_ENTITY_ID: INPUT_ENTITY_ID, - ATTR_OPTION: const.HDMI2, + ATTR_OPTION: cmd.Input.HDMI2, }, blocking=True, ) - - mock_device.remote.assert_called_once_with(const.REMOTE_HDMI_2) + mock_device.set.assert_called_once_with(cmd.Input, cmd.Input.HDMI2) diff --git a/tests/components/jvc_projector/test_sensor.py b/tests/components/jvc_projector/test_sensor.py index 1827363e5ad..87ebe737dec 100644 --- a/tests/components/jvc_projector/test_sensor.py +++ b/tests/components/jvc_projector/test_sensor.py @@ -7,7 +7,7 @@ from homeassistant.helpers import entity_registry as er from tests.common import MockConfigEntry -POWER_ID = "sensor.jvc_projector_power_status" +POWER_ID = "sensor.jvc_projector_status" async def test_entity_state( diff --git a/tests/components/kitchen_sink/snapshots/test_switch.ambr b/tests/components/kitchen_sink/snapshots/test_switch.ambr index 2bee2f1f61c..b93d94b7602 100644 --- a/tests/components/kitchen_sink/snapshots/test_switch.ambr +++ b/tests/components/kitchen_sink/snapshots/test_switch.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -143,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/knocki/snapshots/test_event.ambr b/tests/components/knocki/snapshots/test_event.ambr index 0700e2f48b4..508df6c0ab4 100644 --- a/tests/components/knocki/snapshots/test_event.ambr +++ b/tests/components/knocki/snapshots/test_event.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aaaa', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/kodi/test_device_trigger.py b/tests/components/kodi/test_device_trigger.py index 541a9f781fd..2e797245c24 100644 --- a/tests/components/kodi/test_device_trigger.py +++ b/tests/components/kodi/test_device_trigger.py @@ -15,11 +15,6 @@ from . import init_integration from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture async def kodi_media_player(hass: HomeAssistant) -> str: """Get a kodi media player.""" diff --git a/tests/components/labs/test_init.py b/tests/components/labs/test_init.py index 467201f9240..cc040d11321 100644 --- a/tests/components/labs/test_init.py +++ b/tests/components/labs/test_init.py @@ -11,6 +11,7 @@ from homeassistant.components.labs import ( EVENT_LABS_UPDATED, async_is_preview_feature_enabled, async_listen, + async_update_preview_feature, ) from homeassistant.components.labs.const import DOMAIN, LABS_DATA from homeassistant.components.labs.models import LabPreviewFeature @@ -20,6 +21,8 @@ from homeassistant.setup import async_setup_component from . import assert_stored_labs_data +from tests.common import async_capture_events + async def test_async_setup(hass: HomeAssistant) -> None: """Test the Labs integration setup.""" @@ -436,3 +439,57 @@ async def test_async_listen_helper(hass: HomeAssistant) -> None: # Verify listener was not called after unsubscribe assert len(listener_calls) == 1 + + +async def test_async_update_preview_feature( + hass: HomeAssistant, hass_storage: dict[str, Any] +) -> None: + """Test enabling and disabling a preview feature using the helper function.""" + hass.config.components.add("kitchen_sink") + + assert await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + + events = async_capture_events(hass, EVENT_LABS_UPDATED) + + await async_update_preview_feature( + hass, "kitchen_sink", "special_repair", enabled=True + ) + await hass.async_block_till_done() + + assert async_is_preview_feature_enabled(hass, "kitchen_sink", "special_repair") + + assert len(events) == 1 + assert events[0].data["domain"] == "kitchen_sink" + assert events[0].data["preview_feature"] == "special_repair" + assert events[0].data["enabled"] is True + + assert_stored_labs_data( + hass_storage, + [{"domain": "kitchen_sink", "preview_feature": "special_repair"}], + ) + + await async_update_preview_feature( + hass, "kitchen_sink", "special_repair", enabled=False + ) + await hass.async_block_till_done() + + assert not async_is_preview_feature_enabled(hass, "kitchen_sink", "special_repair") + + assert len(events) == 2 + assert events[1].data["domain"] == "kitchen_sink" + assert events[1].data["preview_feature"] == "special_repair" + assert events[1].data["enabled"] is False + + assert_stored_labs_data(hass_storage, []) + + +async def test_async_update_preview_feature_not_found(hass: HomeAssistant) -> None: + """Test updating a preview feature that doesn't exist raises.""" + assert await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + + with pytest.raises( + ValueError, match="Preview feature nonexistent.feature not found" + ): + await async_update_preview_feature(hass, "nonexistent", "feature", enabled=True) diff --git a/tests/components/lamarzocco/snapshots/test_binary_sensor.ambr b/tests/components/lamarzocco/snapshots/test_binary_sensor.ambr index 0c72fd906a8..a4f180b2355 100644 --- a/tests/components/lamarzocco/snapshots/test_binary_sensor.ambr +++ b/tests/components/lamarzocco/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backflush active', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brewing active', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water tank empty', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'WebSocket connected', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/lamarzocco/snapshots/test_button.ambr b/tests/components/lamarzocco/snapshots/test_button.ambr index 2f6d789b1a0..b8c6a23e656 100644 --- a/tests/components/lamarzocco/snapshots/test_button.ambr +++ b/tests/components/lamarzocco/snapshots/test_button.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start backflush', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lamarzocco/snapshots/test_calendar.ambr b/tests/components/lamarzocco/snapshots/test_calendar.ambr index 60ba292d0f1..2e1f82d0c96 100644 --- a/tests/components/lamarzocco/snapshots/test_calendar.ambr +++ b/tests/components/lamarzocco/snapshots/test_calendar.ambr @@ -104,6 +104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto on/off schedule (aXFz5bJ)', 'options': dict({ }), 'original_device_class': None, @@ -139,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto on/off schedule (Os2OswX)', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lamarzocco/snapshots/test_number.ambr b/tests/components/lamarzocco/snapshots/test_number.ambr index 536d44461ec..d5bfff4b282 100644 --- a/tests/components/lamarzocco/snapshots/test_number.ambr +++ b/tests/components/lamarzocco/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brew by weight dose 1', 'options': dict({ }), 'original_device_class': , @@ -65,6 +66,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brew by weight dose 2', 'options': dict({ }), 'original_device_class': , @@ -162,6 +164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Coffee target temperature', 'options': dict({ }), 'original_device_class': , @@ -221,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart standby time', 'options': dict({ }), 'original_device_class': , @@ -280,6 +284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prebrew off time', 'options': dict({ }), 'original_device_class': , @@ -339,6 +344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prebrew on time', 'options': dict({ }), 'original_device_class': , @@ -398,6 +404,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preinfusion time', 'options': dict({ }), 'original_device_class': , @@ -457,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steam target temperature', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/lamarzocco/snapshots/test_select.ambr b/tests/components/lamarzocco/snapshots/test_select.ambr index f8516b4b89a..8cb7bb50243 100644 --- a/tests/components/lamarzocco/snapshots/test_select.ambr +++ b/tests/components/lamarzocco/snapshots/test_select.ambr @@ -44,6 +44,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brew by weight dose mode', 'options': dict({ }), 'original_device_class': None, @@ -103,6 +104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prebrew/-infusion mode', 'options': dict({ }), 'original_device_class': None, @@ -162,6 +164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prebrew/-infusion mode', 'options': dict({ }), 'original_device_class': None, @@ -221,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prebrew/-infusion mode', 'options': dict({ }), 'original_device_class': None, @@ -278,6 +282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart standby mode', 'options': dict({ }), 'original_device_class': None, @@ -337,6 +342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steam level', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lamarzocco/snapshots/test_sensor.ambr b/tests/components/lamarzocco/snapshots/test_sensor.ambr index 1ded7231287..96349e5e7d3 100644 --- a/tests/components/lamarzocco/snapshots/test_sensor.ambr +++ b/tests/components/lamarzocco/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brewing start time', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Coffee boiler ready time', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last cleaning time', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steam boiler ready time', 'options': dict({ }), 'original_device_class': , @@ -218,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total coffees made', 'options': dict({ }), 'original_device_class': None, @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total flushes done', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lamarzocco/snapshots/test_switch.ambr b/tests/components/lamarzocco/snapshots/test_switch.ambr index c23ef0e55bb..3c4776a9c09 100644 --- a/tests/components/lamarzocco/snapshots/test_switch.ambr +++ b/tests/components/lamarzocco/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto on/off (Os2OswX)', 'options': dict({ }), 'original_device_class': None, @@ -55,6 +56,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto on/off (aXFz5bJ)', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -165,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto on/off (aXFz5bJ)', 'options': dict({ }), 'original_device_class': None, @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto on/off (Os2OswX)', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart standby enabled', 'options': dict({ }), 'original_device_class': None, @@ -309,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steam boiler', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lamarzocco/snapshots/test_update.ambr b/tests/components/lamarzocco/snapshots/test_update.ambr index 951e8a3d9db..9227d433461 100644 --- a/tests/components/lamarzocco/snapshots/test_update.ambr +++ b/tests/components/lamarzocco/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gateway firmware', 'options': dict({ }), 'original_device_class': , @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/lametric/snapshots/test_update.ambr b/tests/components/lametric/snapshots/test_update.ambr index 342cac5b39b..607df87e014 100644 --- a/tests/components/lametric/snapshots/test_update.ambr +++ b/tests/components/lametric/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/lawn_mower/test_trigger.py b/tests/components/lawn_mower/test_trigger.py index decec0b54c8..cb51c8529e4 100644 --- a/tests/components/lawn_mower/test_trigger.py +++ b/tests/components/lawn_mower/test_trigger.py @@ -1,8 +1,6 @@ """Test lawn mower triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, other_states, parametrize_target_entities, @@ -21,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_lawn_mowers(hass: HomeAssistant) -> list[str]: """Create multiple lawn mower entities associated with different targets.""" @@ -64,7 +47,7 @@ async def test_lawn_mower_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("lawn_mower"), @@ -103,7 +86,7 @@ async def test_lawn_mower_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the lawn mower state trigger fires when any lawn mower state changes to a specific state.""" other_entity_ids = set(target_lawn_mowers) - {entity_id} @@ -132,7 +115,7 @@ async def test_lawn_mower_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("lawn_mower"), @@ -171,7 +154,7 @@ async def test_lawn_mower_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the lawn mower state trigger fires when the first lawn mower changes to a specific state.""" other_entity_ids = set(target_lawn_mowers) - {entity_id} @@ -199,7 +182,7 @@ async def test_lawn_mower_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("lawn_mower"), @@ -238,7 +221,7 @@ async def test_lawn_mower_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the lawn_mower state trigger fires when the last lawn_mower changes to a specific state.""" other_entity_ids = set(target_lawn_mowers) - {entity_id} diff --git a/tests/components/lcn/snapshots/test_binary_sensor.ambr b/tests/components/lcn/snapshots/test_binary_sensor.ambr index 1317150b19e..3091443e3d2 100644 --- a/tests/components/lcn/snapshots/test_binary_sensor.ambr +++ b/tests/components/lcn/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Binary_Sensor1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lcn/snapshots/test_climate.ambr b/tests/components/lcn/snapshots/test_climate.ambr index ffc9a2fad4d..437ee8e3b85 100644 --- a/tests/components/lcn/snapshots/test_climate.ambr +++ b/tests/components/lcn/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lcn/snapshots/test_cover.ambr b/tests/components/lcn/snapshots/test_cover.ambr index f59393a8e91..0760cd0a1e3 100644 --- a/tests/components/lcn/snapshots/test_cover.ambr +++ b/tests/components/lcn/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cover_Outputs', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cover_Relays', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cover_Relays_BS4', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cover_Relays_Module', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lcn/snapshots/test_light.ambr b/tests/components/lcn/snapshots/test_light.ambr index 6aaed89818d..3eda9523a89 100644 --- a/tests/components/lcn/snapshots/test_light.ambr +++ b/tests/components/lcn/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light_Output1', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light_Output2', 'options': dict({ }), 'original_device_class': None, @@ -139,6 +141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light_Relay1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lcn/snapshots/test_scene.ambr b/tests/components/lcn/snapshots/test_scene.ambr index 21ba0894063..ab35674065e 100644 --- a/tests/components/lcn/snapshots/test_scene.ambr +++ b/tests/components/lcn/snapshots/test_scene.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Romantic', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Romantic Transition', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lcn/snapshots/test_sensor.ambr b/tests/components/lcn/snapshots/test_sensor.ambr index e96f6ccd643..6e374176c1f 100644 --- a/tests/components/lcn/snapshots/test_sensor.ambr +++ b/tests/components/lcn/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor_Led6', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor_LogicOp1', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor_Setpoint1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -169,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor_Var1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/lcn/snapshots/test_switch.ambr b/tests/components/lcn/snapshots/test_switch.ambr index 89d4d12cf35..ee488b5d26c 100644 --- a/tests/components/lcn/snapshots/test_switch.ambr +++ b/tests/components/lcn/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_Group5', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_KeyLock1', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_Output1', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_Output2', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_Regulator1', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_Relay1', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch_Relay2', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lektrico/snapshots/test_binary_sensor.ambr b/tests/components/lektrico/snapshots/test_binary_sensor.ambr index 11fb3aa5a0a..51e65c2e3a8 100644 --- a/tests/components/lektrico/snapshots/test_binary_sensor.ambr +++ b/tests/components/lektrico/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'EV diode short', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'EV error', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Metering error', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RCD error', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay contacts welded', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermal throttling', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Undervoltage', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/lektrico/snapshots/test_button.ambr b/tests/components/lektrico/snapshots/test_button.ambr index 518b96e8191..94ec13e73de 100644 --- a/tests/components/lektrico/snapshots/test_button.ambr +++ b/tests/components/lektrico/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge start', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge stop', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging schedule override', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/lektrico/snapshots/test_number.ambr b/tests/components/lektrico/snapshots/test_number.ambr index 1fe5f7613a6..68d9e06f191 100644 --- a/tests/components/lektrico/snapshots/test_number.ambr +++ b/tests/components/lektrico/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dynamic limit', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED brightness', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lektrico/snapshots/test_select.ambr b/tests/components/lektrico/snapshots/test_select.ambr index e0d3cbbe755..24315c38c03 100644 --- a/tests/components/lektrico/snapshots/test_select.ambr +++ b/tests/components/lektrico/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load balancing mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lektrico/snapshots/test_sensor.ambr b/tests/components/lektrico/snapshots/test_sensor.ambr index 1d3796ef437..1c89e11ac6d 100644 --- a/tests/components/lektrico/snapshots/test_sensor.ambr +++ b/tests/components/lektrico/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Installation current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -237,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -305,6 +310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Limit reason', 'options': dict({ }), 'original_device_class': , @@ -369,6 +375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -438,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -500,6 +508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -554,6 +563,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/lektrico/snapshots/test_switch.ambr b/tests/components/lektrico/snapshots/test_switch.ambr index 71fb8b599c6..f65213acb7c 100644 --- a/tests/components/lektrico/snapshots/test_switch.ambr +++ b/tests/components/lektrico/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Authentication', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/letpot/snapshots/test_binary_sensor.ambr b/tests/components/letpot/snapshots/test_binary_sensor.ambr index 64596ffcd4b..a25fa6acb7b 100644 --- a/tests/components/letpot/snapshots/test_binary_sensor.ambr +++ b/tests/components/letpot/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low water', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump error', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low nutrients', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low water', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Refill error', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/letpot/snapshots/test_number.ambr b/tests/components/letpot/snapshots/test_number.ambr index 4784cfa695a..c5b93c329c5 100644 --- a/tests/components/letpot/snapshots/test_number.ambr +++ b/tests/components/letpot/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light brightness', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plants age', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/letpot/snapshots/test_select.ambr b/tests/components/letpot/snapshots/test_select.ambr index 5d9ddf0d0d3..43170a580c8 100644 --- a/tests/components/letpot/snapshots/test_select.ambr +++ b/tests/components/letpot/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light brightness', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light mode', 'options': dict({ }), 'original_device_class': None, @@ -139,6 +141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light mode', 'options': dict({ }), 'original_device_class': None, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature unit on display', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/letpot/snapshots/test_sensor.ambr b/tests/components/letpot/snapshots/test_sensor.ambr index 12669bb4110..94e55cea0ea 100644 --- a/tests/components/letpot/snapshots/test_sensor.ambr +++ b/tests/components/letpot/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water level', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/letpot/snapshots/test_switch.ambr b/tests/components/letpot/snapshots/test_switch.ambr index d76f943ccaa..b921d1f14d6 100644 --- a/tests/components/letpot/snapshots/test_switch.ambr +++ b/tests/components/letpot/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm sound', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto mode', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump cycling', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/letpot/snapshots/test_time.ambr b/tests/components/letpot/snapshots/test_time.ambr index 8c3ba0c8c08..be3cf0fabdd 100644 --- a/tests/components/letpot/snapshots/test_time.ambr +++ b/tests/components/letpot/snapshots/test_time.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light off', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light on', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lg_thinq/snapshots/test_climate.ambr b/tests/components/lg_thinq/snapshots/test_climate.ambr index 513405d1005..f77f8f63a03 100644 --- a/tests/components/lg_thinq/snapshots/test_climate.ambr +++ b/tests/components/lg_thinq/snapshots/test_climate.ambr @@ -46,6 +46,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lg_thinq/snapshots/test_event.ambr b/tests/components/lg_thinq/snapshots/test_event.ambr index 3f9e11849ab..234f6c602b8 100644 --- a/tests/components/lg_thinq/snapshots/test_event.ambr +++ b/tests/components/lg_thinq/snapshots/test_event.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lg_thinq/snapshots/test_humidifier.ambr b/tests/components/lg_thinq/snapshots/test_humidifier.ambr index 8fce4087ca1..ea38bea3b6a 100644 --- a/tests/components/lg_thinq/snapshots/test_humidifier.ambr +++ b/tests/components/lg_thinq/snapshots/test_humidifier.ambr @@ -31,6 +31,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -73,4 +74,4 @@ 'last_updated': , 'state': 'on', }) -# --- \ No newline at end of file +# --- diff --git a/tests/components/lg_thinq/snapshots/test_number.ambr b/tests/components/lg_thinq/snapshots/test_number.ambr index 28403ab7337..578627ce97f 100644 --- a/tests/components/lg_thinq/snapshots/test_number.ambr +++ b/tests/components/lg_thinq/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Schedule turn-off', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Schedule turn-on', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delayed start', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/lg_thinq/snapshots/test_sensor.ambr b/tests/components/lg_thinq/snapshots/test_sensor.ambr index 5a8ecd34c70..bcb47da4acf 100644 --- a/tests/components/lg_thinq/snapshots/test_sensor.ambr +++ b/tests/components/lg_thinq/snapshots/test_sensor.ambr @@ -1,4 +1,175 @@ # serializer version: 1 +# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_last_month-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_air_conditioner_energy_last_month', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Energy last month', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Energy last month', + 'platform': 'lg_thinq', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'energy_usage_last_month', + 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_energyUsage_last_month', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_last_month-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Test air conditioner Energy last month', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.test_air_conditioner_energy_last_month', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_this_month-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_air_conditioner_energy_this_month', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Energy this month', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Energy this month', + 'platform': 'lg_thinq', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'energy_usage_this_month', + 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_energyUsage_this_month', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_this_month-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Test air conditioner Energy this month', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.test_air_conditioner_energy_this_month', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_yesterday-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_air_conditioner_energy_yesterday', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Energy yesterday', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Energy yesterday', + 'platform': 'lg_thinq', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'energy_usage_yesterday', + 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_energyUsage_yesterday', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_yesterday-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Test air conditioner Energy yesterday', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.test_air_conditioner_energy_yesterday', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_filter_remaining-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -20,6 +191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter remaining', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -124,6 +297,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -177,6 +351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -230,6 +405,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -281,6 +457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Schedule turn-off', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -334,6 +511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Schedule turn-on', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -387,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Schedule turn-on', 'options': dict({ }), 'original_device_class': , @@ -415,171 +594,3 @@ 'state': '2024-10-10T13:14:00+00:00', }) # --- -# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_yesterday-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.test_air_conditioner_energy_yesterday', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 0, - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Energy yesterday', - 'platform': 'lg_thinq', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'energy_usage_yesterday', - 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_energyUsage_yesterday', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_yesterday-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'energy', - 'friendly_name': 'Test air conditioner Energy yesterday', - 'state_class': , - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.test_air_conditioner_energy_yesterday', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unknown', - }) -# --- -# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_this_month-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.test_air_conditioner_energy_this_month', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 0, - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Energy this month', - 'platform': 'lg_thinq', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'energy_usage_this_month', - 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_energyUsage_this_month', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_this_month-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'energy', - 'friendly_name': 'Test air conditioner Energy this month', - 'state_class': , - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.test_air_conditioner_energy_this_month', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unknown', - }) -# --- -# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_last_month-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.test_air_conditioner_energy_last_month', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - 'sensor': dict({ - 'suggested_display_precision': 0, - }), - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Energy last month', - 'platform': 'lg_thinq', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'energy_usage_last_month', - 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_energyUsage_last_month', - 'unit_of_measurement': , - }) -# --- -# name: test_sensor_entities[air_conditioner][sensor.test_air_conditioner_energy_last_month-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'energy', - 'friendly_name': 'Test air conditioner Energy last month', - 'state_class': , - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.test_air_conditioner_energy_last_month', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unknown', - }) -# --- \ No newline at end of file diff --git a/tests/components/lg_thinq/snapshots/test_switch.ambr b/tests/components/lg_thinq/snapshots/test_switch.ambr index 89aab01d510..da2cb105ddf 100644 --- a/tests/components/lg_thinq/snapshots/test_switch.ambr +++ b/tests/components/lg_thinq/snapshots/test_switch.ambr @@ -1,151 +1,4 @@ # serializer version: 1 -# name: test_switch_entities[washer][switch.test_washer_power-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'switch', - 'entity_category': None, - 'entity_id': 'switch.test_washer_power', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Power', - 'platform': 'lg_thinq', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'operation_power', - 'unique_id': 'MW2-0B530EFD-1ADF-4F54-A2C3-46C37F94C689_main_washer_operation_mode', - 'unit_of_measurement': None, - }) -# --- -# name: test_switch_entities[washer][switch.test_washer_power-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'switch', - 'friendly_name': 'Test washer Power', - }), - 'context': , - 'entity_id': 'switch.test_washer_power', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'off', - }) -# --- -# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_power-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'switch', - 'entity_category': , - 'entity_id': 'switch.test_air_conditioner_power', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Power', - 'platform': 'lg_thinq', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': 'operation_power', - 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_air_con_operation_mode', - 'unit_of_measurement': None, - }) -# --- -# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_power-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'switch', - 'friendly_name': 'Test air conditioner Power', - }), - 'context': , - 'entity_id': 'switch.test_air_conditioner_power', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'on', - }) -# --- -# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_energy_saving-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'switch', - 'entity_category': , - 'entity_id': 'switch.test_air_conditioner_energy_saving', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Energy saving', - 'platform': 'lg_thinq', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_power_save_enabled', - 'unit_of_measurement': None, - }) -# --- -# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_energy_saving-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'switch', - 'friendly_name': 'Test air conditioner Energy saving', - }), - 'context': , - 'entity_id': 'switch.test_air_conditioner_energy_saving', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'off', - }) -# --- # name: test_switch_entities[air_conditioner][switch.test_air_conditioner_air_purify-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -167,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air purify', 'options': dict({ }), 'original_device_class': , @@ -195,6 +49,156 @@ 'state': 'off', }) # --- +# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_energy_saving-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.test_air_conditioner_energy_saving', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Energy saving', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Energy saving', + 'platform': 'lg_thinq', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_power_save_enabled', + 'unit_of_measurement': None, + }) +# --- +# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_energy_saving-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'switch', + 'friendly_name': 'Test air conditioner Energy saving', + }), + 'context': , + 'entity_id': 'switch.test_air_conditioner_energy_saving', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.test_air_conditioner_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power', + 'platform': 'lg_thinq', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'operation_power', + 'unique_id': 'MW2-2E247F93-B570-46A6-B827-920E9E10F966_air_con_operation_mode', + 'unit_of_measurement': None, + }) +# --- +# name: test_switch_entities[air_conditioner][switch.test_air_conditioner_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'switch', + 'friendly_name': 'Test air conditioner Power', + }), + 'context': , + 'entity_id': 'switch.test_air_conditioner_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_switch_entities[washer][switch.test_washer_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.test_washer_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power', + 'platform': 'lg_thinq', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'operation_power', + 'unique_id': 'MW2-0B530EFD-1ADF-4F54-A2C3-46C37F94C689_main_washer_operation_mode', + 'unit_of_measurement': None, + }) +# --- +# name: test_switch_entities[washer][switch.test_washer_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'switch', + 'friendly_name': 'Test washer Power', + }), + 'context': , + 'entity_id': 'switch.test_washer_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_switch_entities[dehumidifier][switch.test_dehumidifier_power-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -243,4 +248,4 @@ 'last_updated': , 'state': 'on', }) -# --- \ No newline at end of file +# --- diff --git a/tests/components/libre_hardware_monitor/snapshots/test_sensor.ambr b/tests/components/libre_hardware_monitor/snapshots/test_sensor.ambr index e61fe131bd3..723689012ac 100644 --- a/tests/components/libre_hardware_monitor/snapshots/test_sensor.ambr +++ b/tests/components/libre_hardware_monitor/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core (Tctl/Tdie) Temperature', 'options': dict({ }), 'original_device_class': None, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU Total Load', 'options': dict({ }), 'original_device_class': None, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Package Power', 'options': dict({ }), 'original_device_class': None, @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Package Temperature', 'options': dict({ }), 'original_device_class': None, @@ -238,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VDDCR SoC Voltage', 'options': dict({ }), 'original_device_class': None, @@ -292,6 +297,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VDDCR Voltage', 'options': dict({ }), 'original_device_class': None, @@ -346,6 +352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '+12V Voltage', 'options': dict({ }), 'original_device_class': None, @@ -400,6 +407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '+5V Voltage', 'options': dict({ }), 'original_device_class': None, @@ -454,6 +462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU Fan Fan', 'options': dict({ }), 'original_device_class': None, @@ -508,6 +517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU Temperature', 'options': dict({ }), 'original_device_class': None, @@ -562,6 +572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump Fan Fan', 'options': dict({ }), 'original_device_class': None, @@ -616,6 +627,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System Fan #1 Fan', 'options': dict({ }), 'original_device_class': None, @@ -669,6 +681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System Temperature', 'options': dict({ }), 'original_device_class': None, @@ -723,6 +736,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vcore Voltage', 'options': dict({ }), 'original_device_class': None, @@ -777,6 +791,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Core Clock', 'options': dict({ }), 'original_device_class': None, @@ -831,6 +846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Core Load', 'options': dict({ }), 'original_device_class': None, @@ -885,6 +901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Core Temperature', 'options': dict({ }), 'original_device_class': None, @@ -939,6 +956,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Fan 1 Fan', 'options': dict({ }), 'original_device_class': None, @@ -993,6 +1011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Fan 2 Fan', 'options': dict({ }), 'original_device_class': None, @@ -1047,6 +1066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Hot Spot Temperature', 'options': dict({ }), 'original_device_class': None, @@ -1101,6 +1121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Memory Clock', 'options': dict({ }), 'original_device_class': None, @@ -1155,6 +1176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Memory Controller Load', 'options': dict({ }), 'original_device_class': None, @@ -1209,6 +1231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Package Power', 'options': dict({ }), 'original_device_class': None, @@ -1263,6 +1286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU PCIe Tx Throughput', 'options': dict({ }), 'original_device_class': None, @@ -1317,6 +1341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU Video Engine Load', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/light/test_condition.py b/tests/components/light/test_condition.py index 8eb9fb4c50c..53725df75c0 100644 --- a/tests/components/light/test_condition.py +++ b/tests/components/light/test_condition.py @@ -1,41 +1,23 @@ """Test light conditions.""" -from collections.abc import Generator -from unittest.mock import patch +from typing import Any import pytest -from homeassistant.components import automation -from homeassistant.const import ( - ATTR_LABEL_ID, - CONF_CONDITION, - CONF_OPTIONS, - CONF_TARGET, - STATE_OFF, - STATE_ON, - STATE_UNAVAILABLE, - STATE_UNKNOWN, -) -from homeassistant.core import HomeAssistant, ServiceCall -from homeassistant.setup import async_setup_component +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant from tests.components import ( + ConditionStateDescription, + assert_condition_gated_by_labs_flag, + create_target_condition, + parametrize_condition_states_all, + parametrize_condition_states_any, parametrize_target_entities, set_or_remove_state, target_entities, ) -INVALID_STATES = [ - {"state": STATE_UNAVAILABLE, "attributes": {}}, - {"state": STATE_UNKNOWN, "attributes": {}}, - {"state": None, "attributes": {}}, -] - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - @pytest.fixture async def target_lights(hass: HomeAssistant) -> list[str]: @@ -49,54 +31,6 @@ async def target_switches(hass: HomeAssistant) -> list[str]: return (await target_entities(hass, "switch"))["included"] -async def setup_automation_with_light_condition( - hass: HomeAssistant, - *, - condition: str, - target: dict, - behavior: str, -) -> None: - """Set up automation with light state condition.""" - await async_setup_component( - hass, - automation.DOMAIN, - { - automation.DOMAIN: { - "trigger": {"platform": "event", "event_type": "test_event"}, - "condition": { - CONF_CONDITION: condition, - CONF_TARGET: target, - CONF_OPTIONS: {"behavior": behavior}, - }, - "action": { - "service": "test.automation", - }, - } - }, - ) - - -async def has_call_after_trigger( - hass: HomeAssistant, service_calls: list[ServiceCall] -) -> bool: - """Check if there are service calls after the trigger event.""" - hass.bus.async_fire("test_event") - await hass.async_block_till_done() - has_calls = len(service_calls) == 1 - service_calls.clear() - return has_calls - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.mark.parametrize( "condition", [ @@ -108,58 +42,49 @@ async def test_light_conditions_gated_by_labs_flag( hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str ) -> None: """Test the light conditions are gated by the labs flag.""" - await setup_automation_with_light_condition( - hass, condition=condition, target={ATTR_LABEL_ID: "test_label"}, behavior="any" - ) - assert ( - "Unnamed automation failed to setup conditions and has been disabled: " - f"Condition '{condition}' requires the experimental 'New triggers and " - "conditions' feature to be enabled in Home Assistant Labs settings " - "(feature flag: 'new_triggers_conditions')" - ) in caplog.text + await assert_condition_gated_by_labs_flag(hass, caplog, condition) -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("condition_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), ) @pytest.mark.parametrize( - ("condition", "target_state", "other_state"), + ("condition", "condition_options", "states"), [ - ( - "light.is_on", - {"state": STATE_ON, "attributes": {}}, - {"state": STATE_OFF, "attributes": {}}, + *parametrize_condition_states_any( + condition="light.is_on", + target_states=[STATE_ON], + other_states=[STATE_OFF], ), - ( - "light.is_off", - {"state": STATE_OFF, "attributes": {}}, - {"state": STATE_ON, "attributes": {}}, + *parametrize_condition_states_any( + condition="light.is_off", + target_states=[STATE_OFF], + other_states=[STATE_ON], ), ], ) async def test_light_state_condition_behavior_any( hass: HomeAssistant, - service_calls: list[ServiceCall], target_lights: list[str], target_switches: list[str], condition_target_config: dict, entity_id: str, entities_in_target: int, condition: str, - target_state: str, - other_state: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], ) -> None: """Test the light state condition with the 'any' behavior.""" other_entity_ids = set(target_lights) - {entity_id} # Set all lights, including the tested light, to the initial state for eid in target_lights: - set_or_remove_state(hass, eid, other_state) + set_or_remove_state(hass, eid, states[0]["included"]) await hass.async_block_till_done() - await setup_automation_with_light_condition( + condition = await create_target_condition( hass, condition=condition, target=condition_target_config, @@ -167,70 +92,54 @@ async def test_light_state_condition_behavior_any( ) # Set state for switches to ensure that they don't impact the condition - for eid in target_switches: - set_or_remove_state(hass, eid, other_state) - await hass.async_block_till_done() - assert not await has_call_after_trigger(hass, service_calls) + for state in states: + for eid in target_switches: + set_or_remove_state(hass, eid, state["included"]) + await hass.async_block_till_done() + assert condition(hass) is False - for eid in target_switches: - set_or_remove_state(hass, eid, target_state) - await hass.async_block_till_done() - assert not await has_call_after_trigger(hass, service_calls) + for state in states: + included_state = state["included"] + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] - # Set one light to the condition state -> condition pass - set_or_remove_state(hass, entity_id, target_state) - assert await has_call_after_trigger(hass, service_calls) - - # Set all remaining lights to the condition state -> condition pass - for eid in other_entity_ids: - set_or_remove_state(hass, eid, target_state) - assert await has_call_after_trigger(hass, service_calls) - - for invalid_state in INVALID_STATES: - # Set one light to the invalid state -> condition pass if there are - # other lights in the condition state - set_or_remove_state(hass, entity_id, invalid_state) - assert await has_call_after_trigger(hass, service_calls) == bool( - entities_in_target - 1 - ) - - for invalid_state in INVALID_STATES: - # Set all lights to invalid state -> condition fail - for eid in other_entity_ids: - set_or_remove_state(hass, eid, invalid_state) - assert not await has_call_after_trigger(hass, service_calls) + # Check if changing other lights also passes the condition + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("condition_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), ) @pytest.mark.parametrize( - ("condition", "target_state", "other_state"), + ("condition", "condition_options", "states"), [ - ( - "light.is_on", - {"state": STATE_ON, "attributes": {}}, - {"state": STATE_OFF, "attributes": {}}, + *parametrize_condition_states_all( + condition="light.is_on", + target_states=[STATE_ON], + other_states=[STATE_OFF], ), - ( - "light.is_off", - {"state": STATE_OFF, "attributes": {}}, - {"state": STATE_ON, "attributes": {}}, + *parametrize_condition_states_all( + condition="light.is_off", + target_states=[STATE_OFF], + other_states=[STATE_ON], ), ], ) async def test_light_state_condition_behavior_all( hass: HomeAssistant, - service_calls: list[ServiceCall], target_lights: list[str], condition_target_config: dict, entity_id: str, entities_in_target: int, condition: str, - target_state: str, - other_state: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], ) -> None: """Test the light state condition with the 'all' behavior.""" # Set state for two switches to ensure that they don't impact the condition @@ -241,37 +150,25 @@ async def test_light_state_condition_behavior_all( # Set all lights, including the tested light, to the initial state for eid in target_lights: - set_or_remove_state(hass, eid, other_state) + set_or_remove_state(hass, eid, states[0]["included"]) await hass.async_block_till_done() - await setup_automation_with_light_condition( + condition = await create_target_condition( hass, condition=condition, target=condition_target_config, behavior="all", ) - # No lights on the condition state - assert not await has_call_after_trigger(hass, service_calls) + for state in states: + included_state = state["included"] - # Set one light to the condition state -> condition fail - set_or_remove_state(hass, entity_id, target_state) - assert await has_call_after_trigger(hass, service_calls) == ( - entities_in_target == 1 - ) + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true_first_entity"] - # Set all remaining lights to the condition state -> condition pass - for eid in other_entity_ids: - set_or_remove_state(hass, eid, target_state) - assert await has_call_after_trigger(hass, service_calls) + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() - for invalid_state in INVALID_STATES: - # Set one light to the invalid state -> condition still pass - set_or_remove_state(hass, entity_id, invalid_state) - assert await has_call_after_trigger(hass, service_calls) - - for invalid_state in INVALID_STATES: - # Set all lights to unavailable -> condition passes - for eid in other_entity_ids: - set_or_remove_state(hass, eid, invalid_state) - assert await has_call_after_trigger(hass, service_calls) + assert condition(hass) == state["condition_true"] diff --git a/tests/components/light/test_device_action.py b/tests/components/light/test_device_action.py index 1f69b586c9b..1e2a8c531ac 100644 --- a/tests/components/light/test_device_action.py +++ b/tests/components/light/test_device_action.py @@ -27,11 +27,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/light/test_device_condition.py b/tests/components/light/test_device_condition.py index 1dabe6e6071..4dbc98bc884 100644 --- a/tests/components/light/test_device_condition.py +++ b/tests/components/light/test_device_condition.py @@ -26,11 +26,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/light/test_device_trigger.py b/tests/components/light/test_device_trigger.py index 99e0a5e5b93..57d8188e092 100644 --- a/tests/components/light/test_device_trigger.py +++ b/tests/components/light/test_device_trigger.py @@ -31,11 +31,6 @@ DATA_TEMPLATE_ATTRIBUTES = ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/light/test_trigger.py b/tests/components/light/test_trigger.py index cb2f2895b40..8f0c4327623 100644 --- a/tests/components/light/test_trigger.py +++ b/tests/components/light/test_trigger.py @@ -1,20 +1,29 @@ """Test light trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest from homeassistant.components.light import ATTR_BRIGHTNESS -from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, STATE_OFF, STATE_ON +from homeassistant.const import ( + ATTR_LABEL_ID, + CONF_ABOVE, + CONF_BELOW, + CONF_ENTITY_ID, + STATE_OFF, + STATE_ON, +) from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.helpers.trigger import ( + CONF_LOWER_LIMIT, + CONF_THRESHOLD_TYPE, + CONF_UPPER_LIMIT, + ThresholdType, +) from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, - parametrize_numerical_attribute_changed_trigger_states, - parametrize_numerical_attribute_crossed_threshold_trigger_states, parametrize_target_entities, parametrize_trigger_states, set_or_remove_state, @@ -22,27 +31,137 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_lights(hass: HomeAssistant) -> list[str]: """Create multiple light entities associated with different targets.""" return (await target_entities(hass, "light"))["included"] +def parametrize_brightness_changed_trigger_states( + trigger: str, state: str, attribute: str +) -> list[tuple[str, dict[str, Any], list[TriggerStateDescription]]]: + """Parametrize states and expected service call counts for brightness changed triggers. + + Note: The brightness in the trigger configuration is in percentage (0-100) scale, + the underlying attribute in the state is in uint8 (0-255) scale. + """ + return [ + *parametrize_trigger_states( + trigger=trigger, + trigger_options={}, + target_states=[ + (state, {attribute: 0}), + (state, {attribute: 128}), + (state, {attribute: 255}), + ], + other_states=[(state, {attribute: None})], + retrigger_on_target_state=True, + ), + *parametrize_trigger_states( + trigger=trigger, + trigger_options={CONF_ABOVE: 10}, + target_states=[ + (state, {attribute: 128}), + (state, {attribute: 255}), + ], + other_states=[ + (state, {attribute: None}), + (state, {attribute: 0}), + ], + retrigger_on_target_state=True, + ), + *parametrize_trigger_states( + trigger=trigger, + trigger_options={CONF_BELOW: 90}, + target_states=[ + (state, {attribute: 0}), + (state, {attribute: 128}), + ], + other_states=[ + (state, {attribute: None}), + (state, {attribute: 255}), + ], + retrigger_on_target_state=True, + ), + ] + + +def parametrize_brightness_crossed_threshold_trigger_states( + trigger: str, state: str, attribute: str +) -> list[tuple[str, dict[str, Any], list[TriggerStateDescription]]]: + """Parametrize states and expected service call counts for brightness crossed threshold triggers. + + Note: The brightness in the trigger configuration is in percentage (0-100) scale, + the underlying attribute in the state is in uint8 (0-255) scale. + """ + return [ + *parametrize_trigger_states( + trigger=trigger, + trigger_options={ + CONF_THRESHOLD_TYPE: ThresholdType.BETWEEN, + CONF_LOWER_LIMIT: 10, + CONF_UPPER_LIMIT: 90, + }, + target_states=[ + (state, {attribute: 128}), + (state, {attribute: 153}), + ], + other_states=[ + (state, {attribute: None}), + (state, {attribute: 0}), + (state, {attribute: 255}), + ], + ), + *parametrize_trigger_states( + trigger=trigger, + trigger_options={ + CONF_THRESHOLD_TYPE: ThresholdType.OUTSIDE, + CONF_LOWER_LIMIT: 10, + CONF_UPPER_LIMIT: 90, + }, + target_states=[ + (state, {attribute: 0}), + (state, {attribute: 255}), + ], + other_states=[ + (state, {attribute: None}), + (state, {attribute: 128}), + (state, {attribute: 153}), + ], + ), + *parametrize_trigger_states( + trigger=trigger, + trigger_options={ + CONF_THRESHOLD_TYPE: ThresholdType.ABOVE, + CONF_LOWER_LIMIT: 10, + }, + target_states=[ + (state, {attribute: 128}), + (state, {attribute: 255}), + ], + other_states=[ + (state, {attribute: None}), + (state, {attribute: 0}), + ], + ), + *parametrize_trigger_states( + trigger=trigger, + trigger_options={ + CONF_THRESHOLD_TYPE: ThresholdType.BELOW, + CONF_UPPER_LIMIT: 90, + }, + target_states=[ + (state, {attribute: 0}), + (state, {attribute: 128}), + ], + other_states=[ + (state, {attribute: None}), + (state, {attribute: 255}), + ], + ), + ] + + @pytest.mark.parametrize( "trigger_key", [ @@ -65,7 +184,7 @@ async def test_light_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), @@ -94,7 +213,7 @@ async def test_light_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the light state trigger fires when any light state changes to a specific state.""" other_entity_ids = set(target_lights) - {entity_id} @@ -123,7 +242,7 @@ async def test_light_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), @@ -131,10 +250,10 @@ async def test_light_state_trigger_behavior_any( @pytest.mark.parametrize( ("trigger", "trigger_options", "states"), [ - *parametrize_numerical_attribute_changed_trigger_states( + *parametrize_brightness_changed_trigger_states( "light.brightness_changed", STATE_ON, ATTR_BRIGHTNESS ), - *parametrize_numerical_attribute_crossed_threshold_trigger_states( + *parametrize_brightness_crossed_threshold_trigger_states( "light.brightness_crossed_threshold", STATE_ON, ATTR_BRIGHTNESS ), ], @@ -148,7 +267,7 @@ async def test_light_state_attribute_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the light state trigger fires when any light state changes to a specific state.""" other_entity_ids = set(target_lights) - {entity_id} @@ -177,7 +296,7 @@ async def test_light_state_attribute_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), @@ -206,7 +325,7 @@ async def test_light_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the light state trigger fires when the first light changes to a specific state.""" other_entity_ids = set(target_lights) - {entity_id} @@ -234,7 +353,7 @@ async def test_light_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), @@ -242,7 +361,7 @@ async def test_light_state_trigger_behavior_first( @pytest.mark.parametrize( ("trigger", "trigger_options", "states"), [ - *parametrize_numerical_attribute_crossed_threshold_trigger_states( + *parametrize_brightness_crossed_threshold_trigger_states( "light.brightness_crossed_threshold", STATE_ON, ATTR_BRIGHTNESS ), ], @@ -286,7 +405,7 @@ async def test_light_state_attribute_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), @@ -315,7 +434,7 @@ async def test_light_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the light state trigger fires when the last light changes to a specific state.""" other_entity_ids = set(target_lights) - {entity_id} @@ -342,7 +461,7 @@ async def test_light_state_trigger_behavior_last( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("light"), @@ -350,7 +469,7 @@ async def test_light_state_trigger_behavior_last( @pytest.mark.parametrize( ("trigger", "trigger_options", "states"), [ - *parametrize_numerical_attribute_crossed_threshold_trigger_states( + *parametrize_brightness_crossed_threshold_trigger_states( "light.brightness_crossed_threshold", STATE_ON, ATTR_BRIGHTNESS ), ], diff --git a/tests/components/litejet/test_trigger.py b/tests/components/litejet/test_trigger.py index de99d701926..068f8022b5f 100644 --- a/tests/components/litejet/test_trigger.py +++ b/tests/components/litejet/test_trigger.py @@ -6,8 +6,6 @@ from typing import Any from unittest import mock from unittest.mock import MagicMock, patch -import pytest - from homeassistant import setup from homeassistant.components import automation from homeassistant.core import HomeAssistant, ServiceCall @@ -17,12 +15,6 @@ from . import async_init_integration from tests.common import async_fire_time_changed_exact - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - _LOGGER = logging.getLogger(__name__) ENTITY_SWITCH = "switch.mock_switch_1" diff --git a/tests/components/lock/test_device_action.py b/tests/components/lock/test_device_action.py index e77e7edd005..ee1edc39eb0 100644 --- a/tests/components/lock/test_device_action.py +++ b/tests/components/lock/test_device_action.py @@ -19,11 +19,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("set_state", "features_reg", "features_state", "expected_action_types"), [ diff --git a/tests/components/lock/test_device_condition.py b/tests/components/lock/test_device_condition.py index 1818d4933b8..3b9f66067bd 100644 --- a/tests/components/lock/test_device_condition.py +++ b/tests/components/lock/test_device_condition.py @@ -15,11 +15,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/lock/test_device_trigger.py b/tests/components/lock/test_device_trigger.py index a5b8e47ef2f..efefa0f4274 100644 --- a/tests/components/lock/test_device_trigger.py +++ b/tests/components/lock/test_device_trigger.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/lock/test_trigger.py b/tests/components/lock/test_trigger.py index f34338ea56d..ec304b116ea 100644 --- a/tests/components/lock/test_trigger.py +++ b/tests/components/lock/test_trigger.py @@ -1,8 +1,6 @@ """Test lock triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, other_states, parametrize_target_entities, @@ -21,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_locks(hass: HomeAssistant) -> list[str]: """Create multiple lock entities associated with different targets.""" @@ -64,7 +47,7 @@ async def test_lock_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -103,7 +86,7 @@ async def test_lock_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the lock state trigger fires when any lock state changes to a specific state.""" other_entity_ids = set(target_locks) - {entity_id} @@ -132,7 +115,7 @@ async def test_lock_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -171,7 +154,7 @@ async def test_lock_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the lock state trigger fires when the first lock changes to a specific state.""" other_entity_ids = set(target_locks) - {entity_id} @@ -199,7 +182,7 @@ async def test_lock_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -238,7 +221,7 @@ async def test_lock_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the lock state trigger fires when the last lock changes to a specific state.""" other_entity_ids = set(target_locks) - {entity_id} diff --git a/tests/components/logbook/conftest.py b/tests/components/logbook/conftest.py deleted file mode 100644 index 8795ba3c018..00000000000 --- a/tests/components/logbook/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Conftest for script tests.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/lunatone/snapshots/test_light.ambr b/tests/components/lunatone/snapshots/test_light.ambr index 46b74ee5180..35014b6f0fa 100644 --- a/tests/components/lunatone/snapshots/test_light.ambr +++ b/tests/components/lunatone/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -138,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/madvr/snapshots/test_binary_sensor.ambr b/tests/components/madvr/snapshots/test_binary_sensor.ambr index 8f82914ae25..ed0cc9ae3fe 100644 --- a/tests/components/madvr/snapshots/test_binary_sensor.ambr +++ b/tests/components/madvr/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HDR flag', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing HDR flag', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power state', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal state', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/madvr/snapshots/test_remote.ambr b/tests/components/madvr/snapshots/test_remote.ambr index 876fa81ed0c..d5ab71afd9d 100644 --- a/tests/components/madvr/snapshots/test_remote.ambr +++ b/tests/components/madvr/snapshots/test_remote.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/madvr/snapshots/test_sensor.ambr b/tests/components/madvr/snapshots/test_sensor.ambr index c6c680260d3..a3f7f45b3c9 100644 --- a/tests/components/madvr/snapshots/test_sensor.ambr +++ b/tests/components/madvr/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aspect decimal', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aspect integer', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aspect name', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Aspect resolution', 'options': dict({ }), 'original_device_class': None, @@ -214,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'GPU temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -326,6 +332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HDMI temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -385,6 +392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming aspect ratio', 'options': dict({ }), 'original_device_class': , @@ -444,6 +452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming bit depth', 'options': dict({ }), 'original_device_class': , @@ -503,6 +512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming black levels', 'options': dict({ }), 'original_device_class': , @@ -563,6 +573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming color space', 'options': dict({ }), 'original_device_class': , @@ -628,6 +639,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming colorimetry', 'options': dict({ }), 'original_device_class': , @@ -686,6 +698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming frame rate', 'options': dict({ }), 'original_device_class': None, @@ -734,6 +747,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming resolution', 'options': dict({ }), 'original_device_class': None, @@ -787,6 +801,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Incoming signal type', 'options': dict({ }), 'original_device_class': , @@ -842,6 +857,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mainboard temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -896,6 +912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Masking decimal', 'options': dict({ }), 'original_device_class': None, @@ -944,6 +961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Masking integer', 'options': dict({ }), 'original_device_class': None, @@ -992,6 +1010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Masking resolution', 'options': dict({ }), 'original_device_class': None, @@ -1046,6 +1065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing bit depth', 'options': dict({ }), 'original_device_class': , @@ -1105,6 +1125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing black levels', 'options': dict({ }), 'original_device_class': , @@ -1165,6 +1186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing color space', 'options': dict({ }), 'original_device_class': , @@ -1230,6 +1252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing colorimetry', 'options': dict({ }), 'original_device_class': , @@ -1288,6 +1311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing frame rate', 'options': dict({ }), 'original_device_class': None, @@ -1336,6 +1360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing resolution', 'options': dict({ }), 'original_device_class': None, @@ -1389,6 +1414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outgoing signal type', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/mastodon/snapshots/test_binary_sensor.ambr b/tests/components/mastodon/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..edd43bfc8fd --- /dev/null +++ b/tests/components/mastodon/snapshots/test_binary_sensor.ambr @@ -0,0 +1,393 @@ +# serializer version: 1 +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_bot-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_bot', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Bot', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Bot', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_bot', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_bot-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Bot', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_bot', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_discoverable-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_discoverable', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Discoverable', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Discoverable', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_discoverable', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_discoverable-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Discoverable', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_discoverable', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_indexable-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_indexable', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Indexable', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Indexable', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_indexable', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_indexable-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Indexable', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_indexable', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_limited-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_limited', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Limited', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Limited', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_limited', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_limited-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Limited', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_limited', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_locked-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_locked', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Locked', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Locked', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_locked', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_locked-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Locked', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_locked', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_memorial-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_memorial', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Memorial', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Memorial', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_memorial', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_memorial-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Memorial', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_memorial', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_moved-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_moved', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Moved', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Moved', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_moved', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_moved-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Moved', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_moved', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_suspended-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_suspended', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Suspended', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Suspended', + 'platform': 'mastodon', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'trwnh_mastodon_social_suspended', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[binary_sensor.mastodon_trwnh_mastodon_social_suspended-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mastodon @trwnh@mastodon.social Suspended', + }), + 'context': , + 'entity_id': 'binary_sensor.mastodon_trwnh_mastodon_social_suspended', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/mastodon/snapshots/test_sensor.ambr b/tests/components/mastodon/snapshots/test_sensor.ambr index db84517b33d..cc3d7c090e7 100644 --- a/tests/components/mastodon/snapshots/test_sensor.ambr +++ b/tests/components/mastodon/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Followers', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Following', 'options': dict({ }), 'original_device_class': None, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Posts', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/mastodon/test_binary_sensor.py b/tests/components/mastodon/test_binary_sensor.py new file mode 100644 index 00000000000..212daebbd38 --- /dev/null +++ b/tests/components/mastodon/test_binary_sensor.py @@ -0,0 +1,28 @@ +"""Tests for the Mastodon binary sensors.""" + +from unittest.mock import patch + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.mark.usefixtures("mock_mastodon_client", "entity_registry_enabled_by_default") +async def test_binary_sensors( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test the binary sensor entities.""" + with patch("homeassistant.components.mastodon.PLATFORMS", [Platform.BINARY_SENSOR]): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) diff --git a/tests/components/matter/conftest.py b/tests/components/matter/conftest.py index d92fca32c3b..5f4c9d8eb98 100644 --- a/tests/components/matter/conftest.py +++ b/tests/components/matter/conftest.py @@ -96,7 +96,8 @@ async def integration_fixture( "eve_energy_20ecn4101", "eve_energy_plug", "eve_energy_plug_patched", - "eve_thermo", + "eve_thermo_v4", + "eve_thermo_v5", "eve_shutter", "eve_weather_sensor", "extended_color_light", @@ -128,6 +129,7 @@ async def integration_fixture( "oven", "pressure_sensor", "pump", + "resideo_x2s_thermostat", "room_airconditioner", "secuyou_smart_lock", "silabs_dishwasher", diff --git a/tests/components/matter/fixtures/nodes/eve_thermo.json b/tests/components/matter/fixtures/nodes/eve_thermo_v4.json similarity index 99% rename from tests/components/matter/fixtures/nodes/eve_thermo.json rename to tests/components/matter/fixtures/nodes/eve_thermo_v4.json index e00b55d2cfc..1bd36bdf2b5 100644 --- a/tests/components/matter/fixtures/nodes/eve_thermo.json +++ b/tests/components/matter/fixtures/nodes/eve_thermo_v4.json @@ -61,7 +61,7 @@ "0/40/0": 17, "0/40/1": "Eve Systems", "0/40/2": 4874, - "0/40/3": "Eve Thermo", + "0/40/3": "Eve Thermo 20EBP1701", "0/40/4": 79, "0/40/5": "", "0/40/6": "**REDACTED**", diff --git a/tests/components/matter/fixtures/nodes/eve_thermo_v5.json b/tests/components/matter/fixtures/nodes/eve_thermo_v5.json new file mode 100644 index 00000000000..1d3c4f018fe --- /dev/null +++ b/tests/components/matter/fixtures/nodes/eve_thermo_v5.json @@ -0,0 +1,593 @@ +{ + "node_id": 12, + "date_commissioned": "2026-01-12T17:05:18.823583", + "last_interview": "2026-01-12T17:12:42.428644", + "interview_version": 6, + "available": true, + "is_bridge": false, + "attributes": { + "0/29/0": [ + { + "0": 18, + "1": 1 + }, + { + "0": 17, + "1": 1 + }, + { + "0": 22, + "1": 3 + } + ], + "0/29/1": [ + 29, 31, 40, 42, 47, 48, 49, 50, 51, 52, 53, 56, 60, 62, 63, 70, 323615744 + ], + "0/29/2": [41], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65533": 2, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/31/0": [ + { + "254": 1 + }, + { + "254": 1 + }, + { + "254": 2 + }, + { + "254": 3 + }, + { + "1": 5, + "2": 2, + "3": [112233], + "4": null, + "254": 4 + } + ], + "0/31/1": [], + "0/31/2": 10, + "0/31/3": 3, + "0/31/4": 5, + "0/31/65532": 1, + "0/31/65533": 2, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/40/0": 18, + "0/40/1": "Eve Systems", + "0/40/2": 4874, + "0/40/3": "Eve Thermo 20ECD1701", + "0/40/4": 125, + "0/40/5": "", + "0/40/6": "**REDACTED**", + "0/40/7": 1, + "0/40/8": "1.1", + "0/40/9": 10287, + "0/40/10": "3.6.5", + "0/40/15": "FX46O1M01234", + "0/40/18": "DF3D0B4137A71234", + "0/40/19": { + "0": 3, + "1": 3 + }, + "0/40/21": 17039616, + "0/40/22": 1, + "0/40/65532": 0, + "0/40/65533": 4, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 18, 19, 21, 22, 65528, 65529, 65531, + 65532, 65533 + ], + "0/42/0": [ + { + "1": 556220604, + "2": 0, + "254": 1 + } + ], + "0/42/1": true, + "0/42/2": 1, + "0/42/3": null, + "0/42/65532": 0, + "0/42/65533": 1, + "0/42/65528": [], + "0/42/65529": [0], + "0/42/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/47/0": 1, + "0/47/1": 0, + "0/47/2": "Battery", + "0/47/11": null, + "0/47/12": 200, + "0/47/14": 0, + "0/47/15": false, + "0/47/16": 2, + "0/47/18": [], + "0/47/19": "", + "0/47/20": 2, + "0/47/25": 2, + "0/47/31": [], + "0/47/65532": 10, + "0/47/65533": 3, + "0/47/65528": [], + "0/47/65529": [], + "0/47/65531": [ + 0, 1, 2, 11, 12, 14, 15, 16, 18, 19, 20, 25, 31, 65528, 65529, 65531, + 65532, 65533 + ], + "0/48/0": 0, + "0/48/1": { + "0": 60, + "1": 900 + }, + "0/48/2": 0, + "0/48/3": 0, + "0/48/4": true, + "0/48/65532": 0, + "0/48/65533": 2, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/49/0": 1, + "0/49/1": [ + { + "0": "p0jbsOzJRNw=", + "1": true + } + ], + "0/49/2": 10, + "0/49/3": 20, + "0/49/4": true, + "0/49/5": 0, + "0/49/6": "p0jbsOzJRNw=", + "0/49/7": null, + "0/49/9": 4, + "0/49/10": 5, + "0/49/65532": 2, + "0/49/65533": 2, + "0/49/65528": [1, 5, 7], + "0/49/65529": [0, 3, 4, 6, 8], + "0/49/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 65528, 65529, 65531, 65532, 65533 + ], + "0/50/65532": 0, + "0/50/65533": 1, + "0/50/65528": [1], + "0/50/65529": [0], + "0/50/65531": [65528, 65529, 65531, 65532, 65533], + "0/51/0": [ + { + "0": "MyHome", + "1": true, + "2": null, + "3": null, + "4": "3jP5Rq6mlcw=", + "5": [], + "6": [ + "/akBUIsgAAB2ykzh+Z7oEA==", + "/QANuACgAAAAAAD//gAsAw==", + "/QANuACgAADNhSwQ0KnuNg==", + "/oAAAAAAAADcM/lGrqaVzA==" + ], + "7": 4 + } + ], + "0/51/1": 9, + "0/51/2": 11, + "0/51/3": 0, + "0/51/5": [], + "0/51/6": [], + "0/51/7": [], + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 2, + "0/51/65528": [2], + "0/51/65529": [0, 1], + "0/51/65531": [0, 1, 2, 3, 5, 6, 7, 8, 65528, 65529, 65531, 65532, 65533], + "0/52/1": 10172, + "0/52/2": 1948, + "0/52/65532": 0, + "0/52/65533": 1, + "0/52/65528": [], + "0/52/65529": [], + "0/52/65531": [1, 2, 65528, 65529, 65531, 65532, 65533], + "0/53/0": 25, + "0/53/1": 2, + "0/53/2": "MyHome", + "0/53/3": 4660, + "0/53/4": 12054125955590472924, + "0/53/5": "QP0ADbgAoAAA", + "0/53/6": 0, + "0/53/7": [ + { + "0": 12864791528929066571, + "1": 12, + "2": 11264, + "3": 1787623, + "4": 77786, + "5": 3, + "6": -50, + "7": -51, + "8": 28, + "9": 0, + "10": true, + "11": true, + "12": true, + "13": false + } + ], + "0/53/8": [ + { + "0": 12864791528929066571, + "1": 11264, + "2": 11, + "3": 0, + "4": 0, + "5": 3, + "6": 0, + "7": 12, + "8": true, + "9": true + } + ], + "0/53/9": 1775826714, + "0/53/10": 64, + "0/53/11": 96, + "0/53/12": 247, + "0/53/13": 57, + "0/53/14": 1, + "0/53/15": 1, + "0/53/16": 0, + "0/53/17": 0, + "0/53/18": 0, + "0/53/19": 1, + "0/53/20": 0, + "0/53/21": 0, + "0/53/22": 795, + "0/53/23": 795, + "0/53/24": 0, + "0/53/25": 796, + "0/53/26": 797, + "0/53/27": 0, + "0/53/28": 687, + "0/53/29": 161, + "0/53/30": 0, + "0/53/31": 0, + "0/53/32": 0, + "0/53/33": 466, + "0/53/34": 0, + "0/53/35": 0, + "0/53/36": 0, + "0/53/37": 0, + "0/53/38": 0, + "0/53/39": 251, + "0/53/40": 143, + "0/53/41": 0, + "0/53/42": 142, + "0/53/43": 0, + "0/53/44": 0, + "0/53/45": 0, + "0/53/46": 0, + "0/53/47": 0, + "0/53/48": 98, + "0/53/49": 1, + "0/53/50": 2, + "0/53/51": 0, + "0/53/52": 0, + "0/53/53": 0, + "0/53/54": 7, + "0/53/55": 1, + "0/53/59": { + "0": 672, + "1": 143 + }, + "0/53/60": "AB//4A==", + "0/53/61": { + "0": true, + "1": false, + "2": true, + "3": true, + "4": true, + "5": true, + "6": false, + "7": true, + "8": true, + "9": true, + "10": true, + "11": true + }, + "0/53/62": [], + "0/53/65532": 15, + "0/53/65533": 3, + "0/53/65528": [], + "0/53/65529": [0], + "0/53/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 59, + 60, 61, 62, 65528, 65529, 65531, 65532, 65533 + ], + "0/56/0": null, + "0/56/1": 0, + "0/56/2": 0, + "0/56/3": null, + "0/56/5": [ + { + "0": 3600, + "1": 0, + "2": "Europe/Paris" + } + ], + "0/56/6": [ + { + "0": 0, + "1": 0, + "2": 828061200000000 + }, + { + "0": 3600, + "1": 828061200000000, + "2": 846205200000000 + } + ], + "0/56/7": null, + "0/56/8": 2, + "0/56/10": 2, + "0/56/11": 2, + "0/56/65532": 9, + "0/56/65533": 2, + "0/56/65528": [3], + "0/56/65529": [0, 1, 2, 4], + "0/56/65531": [ + 0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 65528, 65529, 65531, 65532, 65533 + ], + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65532": 1, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 1, 2], + "0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533], + "0/62/0": [ + { + "254": 1 + }, + { + "254": 2 + }, + { + "254": 3 + }, + { + "1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRDBgkBwEkCAEwCUEEjpEdjgSj9HS+HEJVD/GpyTr4aD+5fAti/w8n4eIrPgWZGhqCV0qnqaWVnQ15JLw/y001clUJvTA0F6aotXHi6zcKNQEoARgkAgE2AwQCBAEYMAQU93OvKOKKLhOjzDp+3jm7VZEuC/MwBRRa34d1hFPuca7UFWclq9cFnlPhShgwC0DDZdbO0KEk7s3FtbyASnf25X/Rwj9BNpBNviVDFPpR2hnkqttW8rmplsec7DeAiYNDGqxt5shN8rNfJHpr9+Q2GA==", + "2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEAV5qZprx2HWOKSP2iCzsI7A0CHgZVtbwsQ/y4ssETfB9z00733STIN0AfD552Vi1h6fJSeEg0/pA82bJL/y0azcKNQEpARgkAmAwBBRa34d1hFPuca7UFWclq9cFnlPhSjAFFG9oKFV1nAO5dx/+jKvq8o8oKcZbGDALQDD8OnB1NcHRxx387f9wZeFDYf32VZ3ZENQrlWBTQZqEKP+K6XjWmjTWttDEeW1kiNtB1T5ZBIaJUxVdqMuNQx8Y", + "254": 4 + } + ], + "0/62/1": [ + { + "1": "BIGMMa0wfrcohBn60cI5V0xt+DIkLSV24OUKndKIXUVuzH8GGO72Yl/9IfYSPDKlK2pRWlT3J4IQD9DEiZtWK6k=", + "2": 4937, + "3": 3003885711, + "4": 3179312192, + "5": "Home", + "254": 1 + } + ], + "0/62/2": 5, + "0/62/3": 4, + "0/62/4": [ + "FTABAQAkAgE3AyYUyakYCSYVj6gLsxgmBMfk9zAkBQA3BiYUyakYCSYVj6gLsxgkBwEkCAEwCUEEgYwxrTB+tyiEGfrRwjlXTG34MiQtJXbg5Qqd0ohdRW7MfwYY7vZiX/0h9hI8MqUralFaVPcnghAP0MSJm1YrqTcKNQEpARgkAmAwBBS3BS9aJzt+p6i28Nj+trB2Uu+vdzAFFLcFL1onO36nqLbw2P62sHZS7693GDALQCm96olCh4FdOmdpai/048NktfVtRdSntFc2qDrwkfljr0v13vTxADZ8mUF2TxEmi0EpXiYLp6rcLm7SNOdQlSgY", + "FTABAQAkAgE3AycUQhmZbaIbYjokFQIYJgRWZLcqJAUANwYnFEIZmW2iG2I6JBUCGCQHASQIATAJQQT2AlKGW/kOMjqayzeO0md523/fuhrhGEUU91uQpTiKo0I7wcPpKnmrwfQNPX6g0kEQl+VGaXa3e22lzfu5Tzp0Nwo1ASkBGCQCYDAEFOOMk13ScMKuT2hlaydi1yEJnhTqMAUU44yTXdJwwq5PaGVrJ2LXIQmeFOoYMAtAv2jJd1qd5miXbYesH1XrJ+vgyY0hzGuZ78N6Jw4Cb1oN1sLSpA+PNM0u7+hsEqcSvvn2eSV8EaRR+hg5YQjHDxg=", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEiuu42juvSBfqPqWrV0OLnN4rePFxNq+O3ajhp0IJIJi1vE5qR9vsLcZeqBXgvO6UVKKdt7CZiR2oUEeqbmnG9TcKNQEpARgkAmAwBBTjAjvCZO2QpJyarhRj7T8yYjarAzAFFOMCO8Jk7ZCknJquFGPtPzJiNqsDGDALQE7hTxTRg92QOxwA1hK3xv8DaxvxL71r6ZHcNRzug9wNnonJ+NC84SFKvKDxwcBxHYqFdIyDiDgwJNTQIBgasmIY", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEbUU9qPxT8hkwnSWRhFacvs82vrsjsaZsqqvM48qn3YZZmQwtvEeyRKl6EDEzFbqd6lAdav4Sr0sunvDLgIHtrjcKNQEpARgkAmAwBBRvaChVdZwDuXcf/oyr6vKPKCnGWzAFFG9oKFV1nAO5dx/+jKvq8o8oKcZbGDALQLa3jnnqN0/o6VG8wM4V9FDzrgDfKPd5cn3BBz77K80Jzo/aNotaTNOa6zX//yIvOkBZfGyq1Dh1vXZ4g2NKcXoY" + ], + "0/62/5": 4, + "0/62/65532": 0, + "0/62/65533": 1, + "0/62/65528": [1, 3, 5, 8], + "0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11], + "0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533], + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65532": 0, + "0/63/65533": 2, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/70/0": 120, + "0/70/1": 300, + "0/70/2": 2000, + "0/70/65532": 0, + "0/70/65533": 3, + "0/70/65528": [], + "0/70/65529": [], + "0/70/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533], + "0/323615744/1": true, + "0/323615744/65532": 0, + "0/323615744/65533": 1, + "0/323615744/65528": [], + "0/323615744/65529": [], + "0/323615744/65531": [1, 65528, 65529, 65531, 65532, 65533], + "1/3/0": 0, + "1/3/1": 4, + "1/3/65532": 0, + "1/3/65533": 5, + "1/3/65528": [], + "1/3/65529": [0], + "1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "1/29/0": [ + { + "0": 769, + "1": 4 + } + ], + "1/29/1": [3, 29, 30, 513, 516, 319486977], + "1/29/2": [1026], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65533": 2, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/30/0": [], + "1/30/65532": 0, + "1/30/65533": 1, + "1/30/65528": [], + "1/30/65529": [], + "1/30/65531": [0, 65528, 65529, 65531, 65532, 65533], + "1/513/0": 1620, + "1/513/3": 1000, + "1/513/4": 3000, + "1/513/16": -15, + "1/513/18": 1750, + "1/513/21": 1000, + "1/513/22": 3000, + "1/513/26": 0, + "1/513/27": 2, + "1/513/28": 4, + "1/513/35": 0, + "1/513/36": 0, + "1/513/41": 0, + "1/513/48": 0, + "1/513/49": 0, + "1/513/50": 0, + "1/513/72": [ + { + "0": 1, + "1": 1, + "2": 2 + }, + { + "0": 2, + "1": 1, + "2": 2 + }, + { + "0": 3, + "1": 1, + "2": 2 + }, + { + "0": 4, + "1": 1, + "2": 2 + }, + { + "0": 5, + "1": 1, + "2": 2 + }, + { + "0": 6, + "1": 1, + "2": 2 + }, + { + "0": 254, + "1": 1, + "2": 2 + } + ], + "1/513/74": 8, + "1/513/78": null, + "1/513/80": [ + { + "0": "AQ==", + "1": 1, + "2": "Home", + "4": 2200, + "5": true + }, + { + "0": "Ag==", + "1": 2, + "2": "Away", + "4": 1800, + "5": true + }, + { + "0": "Aw==", + "1": 3, + "2": "Sleep", + "4": 2000, + "5": false + }, + { + "0": "BA==", + "1": 4, + "2": "Wake", + "4": 2300, + "5": false + }, + { + "0": "BQ==", + "1": 5, + "2": "Vacation", + "4": 1600, + "5": false + }, + { + "0": "Bg==", + "1": 6, + "2": "GoingToSleep", + "4": 2100, + "5": false + }, + { + "0": "/g==", + "1": 254, + "2": "Eco", + "4": 1600, + "5": false + } + ], + "1/513/82": 0, + "1/513/65532": 257, + "1/513/65533": 8, + "1/513/65528": [253], + "1/513/65529": [0, 6, 254], + "1/513/65531": [ + 0, 3, 4, 16, 18, 21, 22, 26, 27, 28, 35, 36, 41, 48, 49, 50, 72, 74, 78, + 80, 82, 65528, 65529, 65531, 65532, 65533 + ], + "1/516/0": 0, + "1/516/1": 0, + "1/516/2": 0, + "1/516/65532": 0, + "1/516/65533": 2, + "1/516/65528": [], + "1/516/65529": [], + "1/516/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533], + "1/319486977/319422464": "AAJ9AAsCAAADAjYoBAxGWDQ2TzFNMDM2NDecAQD/BAECAyz5AQEdAQj/BCUCVQY7DTEuMC4xNS8yLjIuMAA8AQA3AQA/AQAmAQAnAQBPBgAAICAoKP8DIwHx/wYmBCXZAiD/BDQCmAhFBQUAAAAARgkFAAAADgAAQgZJBgUMCBCAAUQRBQAABQMAAAAAAAAAAAAAAABHEQUAAAAAAAAAAAAAAAAAAAAASAYFAAAAAABKBgUAAAAAAP8LIgkQAAAAAAAAAAA=", + "1/319486977/319422466": "bwIAAAAAAAAAAAAABgECEQIQARIBHQE0Ag0AABAAAAAAAgAAAAEBAA==", + "1/319486977/319422467": "FQQAAAACAAAAgAAAAAAAAAAAAAAA", + "1/319486977/319422476": 0, + "1/319486977/319422482": 11267, + "1/319486977/319422487": false, + "1/319486977/319422488": 0, + "1/319486977/319422489": 30240, + "1/319486977/319422490": 262144, + "1/319486977/65532": 0, + "1/319486977/65533": 1, + "1/319486977/65528": [], + "1/319486977/65529": [319422464], + "1/319486977/65531": [ + 65528, 65529, 65531, 319422464, 319422465, 319422466, 319422467, + 319422468, 319422469, 319422476, 319422482, 319422487, 319422488, + 319422489, 319422490, 65532, 65533 + ] + }, + "attribute_subscriptions": [] +} diff --git a/tests/components/matter/fixtures/nodes/resideo_x2s_thermostat.json b/tests/components/matter/fixtures/nodes/resideo_x2s_thermostat.json new file mode 100644 index 00000000000..32a9f3839bb --- /dev/null +++ b/tests/components/matter/fixtures/nodes/resideo_x2s_thermostat.json @@ -0,0 +1,190 @@ +{ + "node_id": 4, + "date_commissioned": "2026-01-04T01:49:35.244151", + "last_interview": "2026-01-04T03:11:54.520702", + "interview_version": 6, + "available": true, + "is_bridge": false, + "attributes": { + "0/29/0": [ + { + "0": 22, + "1": 1 + } + ], + "0/29/1": [29, 31, 40, 48, 51, 60, 62, 63], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65533": 2, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/31/0": [ + { + "1": 5, + "2": 2, + "3": [112233], + "4": null, + "254": 1 + } + ], + "0/31/2": 4, + "0/31/3": 3, + "0/31/4": 4, + "0/31/65532": 0, + "0/31/65533": 1, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [0, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/40/0": 17, + "0/40/1": "Resideo", + "0/40/2": 4890, + "0/40/3": "X2S Smart Thermostat", + "0/40/4": 4096, + "0/40/5": "", + "0/40/6": "**REDACTED**", + "0/40/7": 2, + "0/40/8": "X2S_STAT_NPS_002", + "0/40/9": 1, + "0/40/10": "2.0.0.0", + "0/40/15": "**REDACTED**", + "0/40/19": { + "0": 3, + "1": 3 + }, + "0/40/21": 16973824, + "0/40/22": 1, + "0/40/65532": 0, + "0/40/65533": 3, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 19, 21, 22, 65528, 65529, 65531, + 65532, 65533 + ], + "0/48/0": 0, + "0/48/1": { + "0": 60, + "1": 900 + }, + "0/48/2": 0, + "0/48/3": 2, + "0/48/4": true, + "0/48/65532": 0, + "0/48/65533": 1, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/51/0": [ + { + "0": "r0", + "1": true, + "2": null, + "3": null, + "4": "XPzhnNpQ", + "5": ["wKgJoQ=="], + "6": ["/oAAAAAAAABe/OH//pzaUA=="], + "7": 1 + } + ], + "0/51/1": 2, + "0/51/2": 5105, + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 2, + "0/51/65528": [2], + "0/51/65529": [0, 1], + "0/51/65531": [0, 1, 2, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65532": 0, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 2], + "0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533], + "0/62/0": [ + { + "1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRBBgkBwEkCAEwCUEEKl96Nj13XjcDn1kF4aoFwMWb9leBXP2Urts/tvLi1DF1UZkPEBrfZ5YYqd5tps3ELof6pBX91oACxfbnYF7UyzcKNQEoARgkAgE2AwQCBAEYMAQUY8nv41nGGNtJapsJ0+8/6EAnt9owBRRnrnI3xp/0zhgwIJN0RMbKS99orRgwC0BsruLcJINuIyVVZHD5AlYCuha4XhnLxtIjyYCXIIHGNuu39D6u/j94efSHPrOvVjAHXY56+z5KJguTzlTBOC5tGA==", + "2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEOoay7Kv2Hog5xV7knNJLl+Ywx5Sr/jrp6/PV5XF57NXm4UJfgdb6Ja7rZ+965UjigpYh+JVAVvCRK1xNgkikiDcKNQEpARgkAmAwBBRnrnI3xp/0zhgwIJN0RMbKS99orTAFFEHaAQy9nUPjHiRv7FIwcIp50v+EGDALQF5JHY0EJKgFC63BM4uO0mrkHpeTCSDpUEEz7IsvkdxAgUToWftgJSC3B7gqDelohC4uqReJpmeQ64F5XqYtB3AY", + "254": 1 + } + ], + "0/62/1": [ + { + "1": "BGkTBQSFwwkc5WoOUncXmIahsjWs9bKfHyZRWpArIFMjhyjNKqURWvFS8xbVXTFf+UlFmJF2JnlMX4WgKjXkOLo=", + "2": 4939, + "3": 2, + "4": 4, + "5": "Home", + "254": 1 + } + ], + "0/62/2": 5, + "0/62/3": 1, + "0/62/4": [ + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEaRMFBIXDCRzlag5SdxeYhqGyNaz1sp8fJlFakCsgUyOHKM0qpRFa8VLzFtVdMV/5SUWYkXYmeUxfhaAqNeQ4ujcKNQEpARgkAmAwBBRB2gEMvZ1D4x4kb+xSMHCKedL/hDAFFEHaAQy9nUPjHiRv7FIwcIp50v+EGDALQE/fBBea6WzXom6INogGzGdop0w7g8j4dcIo6v8Id2k+sttWqeL5we7dDJonx/m2MgVsQTKCeVhtN/nzT4stvmEY" + ], + "0/62/5": 1, + "0/62/65532": 0, + "0/62/65533": 1, + "0/62/65528": [1, 3, 5, 8], + "0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11], + "0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533], + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65532": 0, + "0/63/65533": 2, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/3/0": 0, + "1/3/1": 4, + "1/3/65532": 0, + "1/3/65533": 4, + "1/3/65528": [], + "1/3/65529": [0], + "1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "1/4/0": 128, + "1/4/65532": 1, + "1/4/65533": 4, + "1/4/65528": [0, 1, 2, 3], + "1/4/65529": [0, 1, 2, 3, 4, 5], + "1/4/65531": [0, 65528, 65529, 65531, 65532, 65533], + "1/29/0": [ + { + "0": 769, + "1": 1 + } + ], + "1/29/1": [3, 4, 29, 513], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65533": 2, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/513/0": 2055, + "1/513/3": 443, + "1/513/4": 3221, + "1/513/5": 1000, + "1/513/6": 3721, + "1/513/17": 2666, + "1/513/18": 2166, + "1/513/25": 0, + "1/513/27": 4, + "1/513/28": 0, + "1/513/65532": 3, + "1/513/65533": 6, + "1/513/65528": [], + "1/513/65529": [0], + "1/513/65531": [ + 0, 3, 4, 5, 6, 17, 18, 25, 27, 28, 65528, 65529, 65531, 65532, 65533 + ] + }, + "attribute_subscriptions": [] +} diff --git a/tests/components/matter/snapshots/test_binary_sensor.ambr b/tests/components/matter/snapshots/test_binary_sensor.ambr index 8c816c8b705..37a418de972 100644 --- a/tests/components/matter/snapshots/test_binary_sensor.ambr +++ b/tests/components/matter/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -342,7 +349,7 @@ 'state': 'on', }) # --- -# name: test_binary_sensors[eve_shutter][binary_sensor.eve_shutter_switch_20eci1701_problem-entry] +# name: test_binary_sensors[eve_shutter][binary_sensor.eve_shutter_switch_20eci1701_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -355,7 +362,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.eve_shutter_switch_20eci1701_problem', + 'entity_id': 'binary_sensor.eve_shutter_switch_20eci1701_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -363,35 +370,36 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-0000000000000094-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[eve_shutter][binary_sensor.eve_shutter_switch_20eci1701_problem-state] +# name: test_binary_sensors[eve_shutter][binary_sensor.eve_shutter_switch_20eci1701_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Eve Shutter Switch 20ECI1701 Problem', + 'friendly_name': 'Eve Shutter Switch 20ECI1701 Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.eve_shutter_switch_20eci1701_problem', + 'entity_id': 'binary_sensor.eve_shutter_switch_20eci1701_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_local_temperature_remote_sensing-entry] +# name: test_binary_sensors[eve_thermo_v4][binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -404,7 +412,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.eve_thermo_local_temperature_remote_sensing', + 'entity_id': 'binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local temperature remote sensing', 'options': dict({ }), 'original_device_class': None, @@ -426,20 +435,20 @@ 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_local_temperature_remote_sensing-state] +# name: test_binary_sensors[eve_thermo_v4][binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'Eve Thermo Local temperature remote sensing', + 'friendly_name': 'Eve Thermo 20EBP1701 Local temperature remote sensing', }), 'context': , - 'entity_id': 'binary_sensor.eve_thermo_local_temperature_remote_sensing', + 'entity_id': 'binary_sensor.eve_thermo_20ebp1701_local_temperature_remote_sensing', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_outdoor_temperature_remote_sensing-entry] +# name: test_binary_sensors[eve_thermo_v5][binary_sensor.eve_thermo_20ecd1701_local_temperature_remote_sensing-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -452,7 +461,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.eve_thermo_outdoor_temperature_remote_sensing', + 'entity_id': 'binary_sensor.eve_thermo_20ecd1701_local_temperature_remote_sensing', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -460,27 +469,28 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local temperature remote sensing', 'options': dict({ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Outdoor temperature remote sensing', + 'original_name': 'Local temperature remote sensing', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': 'thermostat_remote_sensing_outdoor_temperature', - 'unique_id': '00000000000004D2-0000000000000021-MatterNodeDevice-1-ThermostatRemoteSensing_OutdoorTemperature-513-26', + 'translation_key': 'thermostat_remote_sensing_local_temperature', + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-ThermostatRemoteSensing_LocalTemperature-513-26', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[eve_thermo][binary_sensor.eve_thermo_outdoor_temperature_remote_sensing-state] +# name: test_binary_sensors[eve_thermo_v5][binary_sensor.eve_thermo_20ecd1701_local_temperature_remote_sensing-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'Eve Thermo Outdoor temperature remote sensing', + 'friendly_name': 'Eve Thermo 20ECD1701 Local temperature remote sensing', }), 'context': , - 'entity_id': 'binary_sensor.eve_thermo_outdoor_temperature_remote_sensing', + 'entity_id': 'binary_sensor.eve_thermo_20ecd1701_local_temperature_remote_sensing', 'last_changed': , 'last_reported': , 'last_updated': , @@ -508,6 +518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -557,6 +568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water leak', 'options': dict({ }), 'original_device_class': , @@ -606,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -655,6 +668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -704,6 +718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -753,6 +768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local temperature remote sensing', 'options': dict({ }), 'original_device_class': None, @@ -801,6 +817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy remote sensing', 'options': dict({ }), 'original_device_class': None, @@ -849,6 +866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature remote sensing', 'options': dict({ }), 'original_device_class': None, @@ -897,6 +915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -946,6 +965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -995,6 +1015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -1044,6 +1065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -1093,6 +1115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Running', 'options': dict({ }), 'original_device_class': , @@ -1142,6 +1165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door alarm', 'options': dict({ }), 'original_device_class': , @@ -1191,6 +1215,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inflow alarm', 'options': dict({ }), 'original_device_class': , @@ -1240,6 +1265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger supply state', 'options': dict({ }), 'original_device_class': , @@ -1289,6 +1315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -1338,6 +1365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -1387,6 +1415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door alarm', 'options': dict({ }), 'original_device_class': , @@ -1436,6 +1465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boost state', 'options': dict({ }), 'original_device_class': None, @@ -1484,6 +1514,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery alert', 'options': dict({ }), 'original_device_class': , @@ -1533,6 +1564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'End of service', 'options': dict({ }), 'original_device_class': , @@ -1582,6 +1614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hardware fault', 'options': dict({ }), 'original_device_class': , @@ -1631,6 +1664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muted', 'options': dict({ }), 'original_device_class': None, @@ -1679,6 +1713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1728,6 +1763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test in progress', 'options': dict({ }), 'original_device_class': , @@ -1777,6 +1813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'General fault', 'options': dict({ }), 'original_device_class': , @@ -1826,6 +1863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve blocked', 'options': dict({ }), 'original_device_class': , @@ -1875,6 +1913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve leaking', 'options': dict({ }), 'original_device_class': , @@ -1903,7 +1942,7 @@ 'state': 'off', }) # --- -# name: test_binary_sensors[window_covering_full][binary_sensor.mock_full_window_covering_problem-entry] +# name: test_binary_sensors[window_covering_full][binary_sensor.mock_full_window_covering_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1916,7 +1955,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.mock_full_window_covering_problem', + 'entity_id': 'binary_sensor.mock_full_window_covering_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1924,35 +1963,36 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[window_covering_full][binary_sensor.mock_full_window_covering_problem-state] +# name: test_binary_sensors[window_covering_full][binary_sensor.mock_full_window_covering_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Mock Full Window Covering Problem', + 'friendly_name': 'Mock Full Window Covering Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.mock_full_window_covering_problem', + 'entity_id': 'binary_sensor.mock_full_window_covering_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[window_covering_lift][binary_sensor.mock_lift_window_covering_problem-entry] +# name: test_binary_sensors[window_covering_lift][binary_sensor.mock_lift_window_covering_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1965,7 +2005,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.mock_lift_window_covering_problem', + 'entity_id': 'binary_sensor.mock_lift_window_covering_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1973,35 +2013,36 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[window_covering_lift][binary_sensor.mock_lift_window_covering_problem-state] +# name: test_binary_sensors[window_covering_lift][binary_sensor.mock_lift_window_covering_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Mock Lift Window Covering Problem', + 'friendly_name': 'Mock Lift Window Covering Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.mock_lift_window_covering_problem', + 'entity_id': 'binary_sensor.mock_lift_window_covering_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[window_covering_pa_lift][binary_sensor.longan_link_wncv_da01_problem-entry] +# name: test_binary_sensors[window_covering_pa_lift][binary_sensor.longan_link_wncv_da01_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -2014,7 +2055,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.longan_link_wncv_da01_problem', + 'entity_id': 'binary_sensor.longan_link_wncv_da01_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -2022,35 +2063,36 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-0000000000000001-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[window_covering_pa_lift][binary_sensor.longan_link_wncv_da01_problem-state] +# name: test_binary_sensors[window_covering_pa_lift][binary_sensor.longan_link_wncv_da01_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Longan link WNCV DA01 Problem', + 'friendly_name': 'Longan link WNCV DA01 Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.longan_link_wncv_da01_problem', + 'entity_id': 'binary_sensor.longan_link_wncv_da01_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_problem-entry] +# name: test_binary_sensors[window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -2063,7 +2105,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.mock_pa_tilt_window_covering_problem', + 'entity_id': 'binary_sensor.mock_pa_tilt_window_covering_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -2071,35 +2113,36 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_problem-state] +# name: test_binary_sensors[window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Mock PA Tilt Window Covering Problem', + 'friendly_name': 'Mock PA Tilt Window Covering Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.mock_pa_tilt_window_covering_problem', + 'entity_id': 'binary_sensor.mock_pa_tilt_window_covering_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[window_covering_tilt][binary_sensor.mock_tilt_window_covering_problem-entry] +# name: test_binary_sensors[window_covering_tilt][binary_sensor.mock_tilt_window_covering_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -2112,7 +2155,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.mock_tilt_window_covering_problem', + 'entity_id': 'binary_sensor.mock_tilt_window_covering_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -2120,35 +2163,36 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[window_covering_tilt][binary_sensor.mock_tilt_window_covering_problem-state] +# name: test_binary_sensors[window_covering_tilt][binary_sensor.mock_tilt_window_covering_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Mock Tilt Window Covering Problem', + 'friendly_name': 'Mock Tilt Window Covering Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.mock_tilt_window_covering_problem', + 'entity_id': 'binary_sensor.mock_tilt_window_covering_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'off', }) # --- -# name: test_binary_sensors[zemismart_mt25b][binary_sensor.zemismart_mt25b_roller_motor_problem-entry] +# name: test_binary_sensors[zemismart_mt25b][binary_sensor.zemismart_mt25b_roller_motor_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -2161,7 +2205,7 @@ 'disabled_by': None, 'domain': 'binary_sensor', 'entity_category': , - 'entity_id': 'binary_sensor.zemismart_mt25b_roller_motor_problem', + 'entity_id': 'binary_sensor.zemismart_mt25b_roller_motor_configuration_status', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -2169,28 +2213,29 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Configuration status', 'options': dict({ }), 'original_device_class': , 'original_icon': None, - 'original_name': 'Problem', + 'original_name': 'Configuration status', 'platform': 'matter', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'config_status_operational', 'unique_id': '00000000000004D2-000000000000007A-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', 'unit_of_measurement': None, }) # --- -# name: test_binary_sensors[zemismart_mt25b][binary_sensor.zemismart_mt25b_roller_motor_problem-state] +# name: test_binary_sensors[zemismart_mt25b][binary_sensor.zemismart_mt25b_roller_motor_configuration_status-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'problem', - 'friendly_name': 'Zemismart MT25B Roller Motor Problem', + 'friendly_name': 'Zemismart MT25B Roller Motor Configuration status', }), 'context': , - 'entity_id': 'binary_sensor.zemismart_mt25b_roller_motor_problem', + 'entity_id': 'binary_sensor.zemismart_mt25b_roller_motor_configuration_status', 'last_changed': , 'last_reported': , 'last_updated': , diff --git a/tests/components/matter/snapshots/test_button.ambr b/tests/components/matter/snapshots/test_button.ambr index 766198b8cc8..1c5d636bafd 100644 --- a/tests/components/matter/snapshots/test_button.ambr +++ b/tests/components/matter/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter condition', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter condition', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -165,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -214,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (2)', 'options': dict({ }), 'original_device_class': , @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (2)', 'options': dict({ }), 'original_device_class': , @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (3)', 'options': dict({ }), 'original_device_class': , @@ -410,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (4)', 'options': dict({ }), 'original_device_class': , @@ -459,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -508,6 +518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (2)', 'options': dict({ }), 'original_device_class': , @@ -557,6 +568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (3)', 'options': dict({ }), 'original_device_class': , @@ -606,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (4)', 'options': dict({ }), 'original_device_class': , @@ -655,6 +668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (5)', 'options': dict({ }), 'original_device_class': , @@ -704,6 +718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -753,6 +768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (2)', 'options': dict({ }), 'original_device_class': , @@ -802,6 +818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -851,6 +868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -900,6 +918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -949,6 +968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -998,6 +1018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1047,6 +1068,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (0)', 'options': dict({ }), 'original_device_class': , @@ -1096,6 +1118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -1145,6 +1168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1194,6 +1218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (bottom)', 'options': dict({ }), 'original_device_class': , @@ -1243,6 +1268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (top)', 'options': dict({ }), 'original_device_class': , @@ -1292,6 +1318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1341,6 +1368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1390,6 +1418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1418,7 +1447,7 @@ 'state': 'unknown', }) # --- -# name: test_buttons[eve_thermo][button.eve_thermo_identify-entry] +# name: test_buttons[eve_thermo_v4][button.eve_thermo_20ebp1701_identify-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1431,7 +1460,7 @@ 'disabled_by': None, 'domain': 'button', 'entity_category': , - 'entity_id': 'button.eve_thermo_identify', + 'entity_id': 'button.eve_thermo_20ebp1701_identify', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1439,6 +1468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1453,14 +1483,64 @@ 'unit_of_measurement': None, }) # --- -# name: test_buttons[eve_thermo][button.eve_thermo_identify-state] +# name: test_buttons[eve_thermo_v4][button.eve_thermo_20ebp1701_identify-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'identify', - 'friendly_name': 'Eve Thermo Identify', + 'friendly_name': 'Eve Thermo 20EBP1701 Identify', }), 'context': , - 'entity_id': 'button.eve_thermo_identify', + 'entity_id': 'button.eve_thermo_20ebp1701_identify', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_buttons[eve_thermo_v5][button.eve_thermo_20ecd1701_identify-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.eve_thermo_20ecd1701_identify', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Identify', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Identify', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-IdentifyButton-3-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_buttons[eve_thermo_v5][button.eve_thermo_20ecd1701_identify-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'Eve Thermo 20ECD1701 Identify', + }), + 'context': , + 'entity_id': 'button.eve_thermo_20ecd1701_identify', 'last_changed': , 'last_reported': , 'last_updated': , @@ -1488,6 +1568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -1537,6 +1618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (2)', 'options': dict({ }), 'original_device_class': , @@ -1586,6 +1668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1635,6 +1718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter condition', 'options': dict({ }), 'original_device_class': None, @@ -1683,6 +1767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter condition', 'options': dict({ }), 'original_device_class': None, @@ -1731,6 +1816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (Fan)', 'options': dict({ }), 'original_device_class': , @@ -1780,6 +1866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -1829,6 +1916,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -1878,6 +1966,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -1927,6 +2016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (Load Control)', 'options': dict({ }), 'original_device_class': , @@ -1976,6 +2066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -2024,6 +2115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Resume', 'options': dict({ }), 'original_device_class': None, @@ -2072,6 +2164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -2120,6 +2213,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -2168,6 +2262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -2217,6 +2312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -2265,6 +2361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Resume', 'options': dict({ }), 'original_device_class': None, @@ -2313,6 +2410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -2361,6 +2459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -2409,6 +2508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -2458,6 +2558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (0)', 'options': dict({ }), 'original_device_class': , @@ -2507,6 +2608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -2556,6 +2658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -2605,6 +2708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (2)', 'options': dict({ }), 'original_device_class': , @@ -2654,6 +2758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (6)', 'options': dict({ }), 'original_device_class': , @@ -2703,6 +2808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (Config)', 'options': dict({ }), 'original_device_class': , @@ -2752,6 +2858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (Down)', 'options': dict({ }), 'original_device_class': , @@ -2801,6 +2908,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (Up)', 'options': dict({ }), 'original_device_class': , @@ -2850,6 +2958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -2899,6 +3008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -2948,6 +3058,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -2976,6 +3087,56 @@ 'state': 'unknown', }) # --- +# name: test_buttons[resideo_x2s_thermostat][button.x2s_smart_thermostat_identify-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.x2s_smart_thermostat_identify', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Identify', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Identify', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-0000000000000004-MatterNodeDevice-1-IdentifyButton-3-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_buttons[resideo_x2s_thermostat][button.x2s_smart_thermostat_identify-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'X2S Smart Thermostat Identify', + }), + 'context': , + 'entity_id': 'button.x2s_smart_thermostat_identify', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_buttons[secuyou_smart_lock][button.secuyou_smart_lock_identify-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -2997,6 +3158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3046,6 +3208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3095,6 +3258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -3143,6 +3307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -3191,6 +3356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -3239,6 +3405,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3288,6 +3455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -3336,6 +3504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Resume', 'options': dict({ }), 'original_device_class': None, @@ -3384,6 +3553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -3432,6 +3602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -3480,6 +3651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify (1)', 'options': dict({ }), 'original_device_class': , @@ -3529,6 +3701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3578,6 +3751,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cancel boost', 'options': dict({ }), 'original_device_class': None, @@ -3626,6 +3800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3675,6 +3850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-test', 'options': dict({ }), 'original_device_class': None, @@ -3723,6 +3899,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3772,6 +3949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3821,6 +3999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3870,6 +4049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -3919,6 +4099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/matter/snapshots/test_climate.ambr b/tests/components/matter/snapshots/test_climate.ambr index 0538ca3f60b..84f75fd427e 100644 --- a/tests/components/matter/snapshots/test_climate.ambr +++ b/tests/components/matter/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -155,6 +157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -191,7 +194,7 @@ 'state': 'heat', }) # --- -# name: test_climates[eve_thermo][climate.eve_thermo-entry] +# name: test_climates[eve_thermo_v4][climate.eve_thermo_20ebp1701-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -211,7 +214,7 @@ 'disabled_by': None, 'domain': 'climate', 'entity_category': None, - 'entity_id': 'climate.eve_thermo', + 'entity_id': 'climate.eve_thermo_20ebp1701', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -219,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -233,11 +237,11 @@ 'unit_of_measurement': None, }) # --- -# name: test_climates[eve_thermo][climate.eve_thermo-state] +# name: test_climates[eve_thermo_v4][climate.eve_thermo_20ebp1701-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'current_temperature': 21.0, - 'friendly_name': 'Eve Thermo', + 'friendly_name': 'Eve Thermo 20EBP1701', 'hvac_modes': list([ , , @@ -248,7 +252,72 @@ 'temperature': 17.0, }), 'context': , - 'entity_id': 'climate.eve_thermo', + 'entity_id': 'climate.eve_thermo_20ebp1701', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'heat', + }) +# --- +# name: test_climates[eve_thermo_v5][climate.eve_thermo_20ecd1701-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'hvac_modes': list([ + , + , + ]), + 'max_temp': 30.0, + 'min_temp': 10.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'climate', + 'entity_category': None, + 'entity_id': 'climate.eve_thermo_20ecd1701', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-MatterThermostat-513-0', + 'unit_of_measurement': None, + }) +# --- +# name: test_climates[eve_thermo_v5][climate.eve_thermo_20ecd1701-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'current_temperature': 16.2, + 'friendly_name': 'Eve Thermo 20ECD1701', + 'hvac_modes': list([ + , + , + ]), + 'max_temp': 30.0, + 'min_temp': 10.0, + 'supported_features': , + 'temperature': 17.5, + }), + 'context': , + 'entity_id': 'climate.eve_thermo_20ecd1701', 'last_changed': , 'last_reported': , 'last_updated': , @@ -285,6 +354,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -355,6 +425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -396,6 +467,75 @@ 'state': 'heat_cool', }) # --- +# name: test_climates[resideo_x2s_thermostat][climate.x2s_smart_thermostat-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'hvac_modes': list([ + , + , + , + , + ]), + 'max_temp': 32.2, + 'min_temp': 4.4, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'climate', + 'entity_category': None, + 'entity_id': 'climate.x2s_smart_thermostat', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00000000000004D2-0000000000000004-MatterNodeDevice-1-MatterThermostat-513-0', + 'unit_of_measurement': None, + }) +# --- +# name: test_climates[resideo_x2s_thermostat][climate.x2s_smart_thermostat-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'current_temperature': 20.6, + 'friendly_name': 'X2S Smart Thermostat', + 'hvac_modes': list([ + , + , + , + , + ]), + 'max_temp': 32.2, + 'min_temp': 4.4, + 'supported_features': , + 'temperature': 21.7, + }), + 'context': , + 'entity_id': 'climate.x2s_smart_thermostat', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_climates[room_airconditioner][climate.room_airconditioner-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -428,6 +568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -496,6 +637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_cover.ambr b/tests/components/matter/snapshots/test_cover.ambr index 58006ea61c8..c3548526b6d 100644 --- a/tests/components/matter/snapshots/test_cover.ambr +++ b/tests/components/matter/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -173,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -224,6 +228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -275,6 +280,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -325,6 +331,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/matter/snapshots/test_event.ambr b/tests/components/matter/snapshots/test_event.ambr index 56a6c3c6b0c..30b72e6c451 100644 --- a/tests/components/matter/snapshots/test_event.ambr +++ b/tests/components/matter/snapshots/test_event.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (3)', 'options': dict({ }), 'original_device_class': , @@ -90,6 +91,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (4)', 'options': dict({ }), 'original_device_class': , @@ -153,6 +155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (5)', 'options': dict({ }), 'original_device_class': , @@ -216,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button', 'options': dict({ }), 'original_device_class': , @@ -279,6 +283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (1)', 'options': dict({ }), 'original_device_class': , @@ -344,6 +349,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (2)', 'options': dict({ }), 'original_device_class': , @@ -409,6 +415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (1)', 'options': dict({ }), 'original_device_class': , @@ -472,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (2)', 'options': dict({ }), 'original_device_class': , @@ -535,6 +543,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (3)', 'options': dict({ }), 'original_device_class': , @@ -598,6 +607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (4)', 'options': dict({ }), 'original_device_class': , @@ -661,6 +671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (5)', 'options': dict({ }), 'original_device_class': , @@ -724,6 +735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (6)', 'options': dict({ }), 'original_device_class': , @@ -791,6 +803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (1)', 'options': dict({ }), 'original_device_class': , @@ -862,6 +875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (2)', 'options': dict({ }), 'original_device_class': , @@ -930,6 +944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (3)', 'options': dict({ }), 'original_device_class': , @@ -998,6 +1013,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (4)', 'options': dict({ }), 'original_device_class': , @@ -1069,6 +1085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (5)', 'options': dict({ }), 'original_device_class': , @@ -1137,6 +1154,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (6)', 'options': dict({ }), 'original_device_class': , @@ -1205,6 +1223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (7)', 'options': dict({ }), 'original_device_class': , @@ -1276,6 +1295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (8)', 'options': dict({ }), 'original_device_class': , @@ -1344,6 +1364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (9)', 'options': dict({ }), 'original_device_class': , @@ -1411,6 +1432,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (Config)', 'options': dict({ }), 'original_device_class': , @@ -1480,6 +1502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (Down)', 'options': dict({ }), 'original_device_class': , @@ -1549,6 +1572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (Up)', 'options': dict({ }), 'original_device_class': , @@ -1618,6 +1642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (Config)', 'options': dict({ }), 'original_device_class': , @@ -1687,6 +1712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (Down)', 'options': dict({ }), 'original_device_class': , @@ -1756,6 +1782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button (Up)', 'options': dict({ }), 'original_device_class': , @@ -1820,6 +1847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/matter/snapshots/test_fan.ambr b/tests/components/matter/snapshots/test_fan.ambr index 1ec4ad21428..96957609577 100644 --- a/tests/components/matter/snapshots/test_fan.ambr +++ b/tests/components/matter/snapshots/test_fan.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -161,6 +163,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -228,6 +231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -292,6 +296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_light.ambr b/tests/components/matter/snapshots/test_light.ambr index 3aec43a16a9..515874a31b7 100644 --- a/tests/components/matter/snapshots/test_light.ambr +++ b/tests/components/matter/snapshots/test_light.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -105,6 +106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -163,6 +165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -227,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -312,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light (RGB Indicator)', 'options': dict({ }), 'original_device_class': None, @@ -381,6 +386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -437,6 +443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light (1)', 'options': dict({ }), 'original_device_class': None, @@ -501,6 +508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light (6)', 'options': dict({ }), 'original_device_class': None, @@ -570,6 +578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -633,6 +642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -708,6 +718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -777,6 +788,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_lock.ambr b/tests/components/matter/snapshots/test_lock.ambr index c172201f12e..8a55e000ebd 100644 --- a/tests/components/matter/snapshots/test_lock.ambr +++ b/tests/components/matter/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_number.ambr b/tests/components/matter/snapshots/test_number.ambr index b836bece869..24b1706b653 100644 --- a/tests/components/matter/snapshots/test_number.ambr +++ b/tests/components/matter/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hold time', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hold time', 'options': dict({ }), 'original_device_class': None, @@ -115,6 +117,65 @@ 'state': '10', }) # --- +# name: test_numbers[aqara_thermostat_w500][number.floor_heating_thermostat_occupied_setback-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 3.0, + 'min': 0.5, + 'mode': , + 'step': 0.5, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.floor_heating_thermostat_occupied_setback', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Occupied setback', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Occupied setback', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'occupied_setback', + 'unique_id': '00000000000004D2-0000000000000064-MatterNodeDevice-1-ThermostatOccupiedSetback-513-52', + 'unit_of_measurement': , + }) +# --- +# name: test_numbers[aqara_thermostat_w500][number.floor_heating_thermostat_occupied_setback-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Floor Heating Thermostat Occupied setback', + 'max': 3.0, + 'min': 0.5, + 'mode': , + 'step': 0.5, + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'number.floor_heating_thermostat_occupied_setback', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.5', + }) +# --- # name: test_numbers[aqara_u200][number.aqara_smart_lock_u200_user_code_temporary_disable_time-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -141,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code temporary disable time', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrong code limit', 'options': dict({ }), 'original_device_class': None, @@ -256,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -313,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -371,6 +436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -428,6 +494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -486,6 +553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On transition time', 'options': dict({ }), 'original_device_class': None, @@ -544,6 +612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -601,6 +670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -659,6 +729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-relock time', 'options': dict({ }), 'original_device_class': None, @@ -717,6 +788,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code temporary disable time', 'options': dict({ }), 'original_device_class': None, @@ -775,6 +847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrong code limit', 'options': dict({ }), 'original_device_class': None, @@ -832,6 +905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-relock time', 'options': dict({ }), 'original_device_class': None, @@ -890,6 +964,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code temporary disable time', 'options': dict({ }), 'original_device_class': None, @@ -948,6 +1023,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrong code limit', 'options': dict({ }), 'original_device_class': None, @@ -979,7 +1055,7 @@ 'state': '3', }) # --- -# name: test_numbers[eve_thermo][number.eve_thermo_temperature_offset-entry] +# name: test_numbers[eve_thermo_v4][number.eve_thermo_20ebp1701_temperature_offset-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -997,7 +1073,7 @@ 'disabled_by': None, 'domain': 'number', 'entity_category': , - 'entity_id': 'number.eve_thermo_temperature_offset', + 'entity_id': 'number.eve_thermo_20ebp1701_temperature_offset', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1005,6 +1081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -1019,11 +1096,11 @@ 'unit_of_measurement': , }) # --- -# name: test_numbers[eve_thermo][number.eve_thermo_temperature_offset-state] +# name: test_numbers[eve_thermo_v4][number.eve_thermo_20ebp1701_temperature_offset-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'temperature', - 'friendly_name': 'Eve Thermo Temperature offset', + 'friendly_name': 'Eve Thermo 20EBP1701 Temperature offset', 'max': 50, 'min': -50, 'mode': , @@ -1031,13 +1108,73 @@ 'unit_of_measurement': , }), 'context': , - 'entity_id': 'number.eve_thermo_temperature_offset', + 'entity_id': 'number.eve_thermo_20ebp1701_temperature_offset', 'last_changed': , 'last_reported': , 'last_updated': , 'state': '0.0', }) # --- +# name: test_numbers[eve_thermo_v5][number.eve_thermo_20ecd1701_temperature_offset-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 50, + 'min': -50, + 'mode': , + 'step': 0.5, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.eve_thermo_20ecd1701_temperature_offset', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature offset', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Temperature offset', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'temperature_offset', + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-EveTemperatureOffset-513-16', + 'unit_of_measurement': , + }) +# --- +# name: test_numbers[eve_thermo_v5][number.eve_thermo_20ecd1701_temperature_offset-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Eve Thermo 20ECD1701 Temperature offset', + 'max': 50, + 'min': -50, + 'mode': , + 'step': 0.5, + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'number.eve_thermo_20ecd1701_temperature_offset', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '-1.5', + }) +# --- # name: test_numbers[eve_weather_sensor][number.eve_weather_altitude_above_sea_level-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1064,6 +1201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Altitude above sea level', 'options': dict({ }), 'original_device_class': , @@ -1123,6 +1261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -1180,6 +1319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hold time', 'options': dict({ }), 'original_device_class': None, @@ -1238,6 +1378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED off intensity (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -1295,6 +1436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED on intensity (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -1352,6 +1494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off transition time (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -1410,6 +1553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -1467,6 +1611,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level (RGB Indicator)', 'options': dict({ }), 'original_device_class': None, @@ -1524,6 +1669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -1582,6 +1728,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time (RGB Indicator)', 'options': dict({ }), 'original_device_class': None, @@ -1640,6 +1787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On transition time (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -1698,6 +1846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking time', 'options': dict({ }), 'original_device_class': , @@ -1757,6 +1906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-relock time', 'options': dict({ }), 'original_device_class': None, @@ -1815,6 +1965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code temporary disable time', 'options': dict({ }), 'original_device_class': None, @@ -1873,6 +2024,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrong code limit', 'options': dict({ }), 'original_device_class': None, @@ -1930,6 +2082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -1987,6 +2140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED off intensity', 'options': dict({ }), 'original_device_class': None, @@ -2044,6 +2198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED on intensity', 'options': dict({ }), 'original_device_class': None, @@ -2101,6 +2256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2159,6 +2315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level (1)', 'options': dict({ }), 'original_device_class': None, @@ -2216,6 +2373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level (6)', 'options': dict({ }), 'original_device_class': None, @@ -2273,6 +2431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2331,6 +2490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On transition time', 'options': dict({ }), 'original_device_class': None, @@ -2389,6 +2549,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2447,6 +2608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -2504,6 +2666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2562,6 +2725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On transition time', 'options': dict({ }), 'original_device_class': None, @@ -2620,6 +2784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2678,6 +2843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -2735,6 +2901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2793,6 +2960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On transition time', 'options': dict({ }), 'original_device_class': None, @@ -2851,6 +3019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -2909,6 +3078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -2966,6 +3136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -3024,6 +3195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On transition time', 'options': dict({ }), 'original_device_class': None, @@ -3082,6 +3254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -3139,6 +3312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On/Off transition time', 'options': dict({ }), 'original_device_class': None, @@ -3197,6 +3371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature setpoint', 'options': dict({ }), 'original_device_class': None, @@ -3255,6 +3430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On level', 'options': dict({ }), 'original_device_class': None, @@ -3312,6 +3488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ }), 'original_device_class': None, @@ -3370,6 +3547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-relock time', 'options': dict({ }), 'original_device_class': None, @@ -3428,6 +3606,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User code temporary disable time', 'options': dict({ }), 'original_device_class': None, @@ -3486,6 +3665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrong code limit', 'options': dict({ }), 'original_device_class': None, @@ -3543,6 +3723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature setpoint', 'options': dict({ }), 'original_device_class': None, @@ -3601,6 +3782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature setpoint (2)', 'options': dict({ }), 'original_device_class': None, @@ -3659,6 +3841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature setpoint (3)', 'options': dict({ }), 'original_device_class': None, @@ -3717,6 +3900,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -3775,6 +3959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Default open duration', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_select.ambr b/tests/components/matter/snapshots/test_select.ambr index 126acb631bb..b76b87bf65d 100644 --- a/tests/components/matter/snapshots/test_select.ambr +++ b/tests/components/matter/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature display mode', 'options': dict({ }), 'original_device_class': None, @@ -250,7 +254,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'select', - 'entity_category': None, + 'entity_category': , 'entity_id': 'select.aqara_smart_lock_u200_operating_mode', 'has_entity_name': True, 'hidden_by': None, @@ -259,6 +263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating mode', 'options': dict({ }), 'original_device_class': None, @@ -317,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lighting', 'options': dict({ }), 'original_device_class': None, @@ -377,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -437,6 +444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature level', 'options': dict({ }), 'original_device_class': None, @@ -506,6 +514,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED Color', 'options': dict({ }), 'original_device_class': None, @@ -576,6 +585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -637,6 +647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -687,7 +698,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'select', - 'entity_category': None, + 'entity_category': , 'entity_id': 'select.mock_door_lock_operating_mode', 'has_entity_name': True, 'hidden_by': None, @@ -696,6 +707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating mode', 'options': dict({ }), 'original_device_class': None, @@ -755,6 +767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -816,6 +829,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound volume', 'options': dict({ }), 'original_device_class': None, @@ -866,7 +880,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'select', - 'entity_category': None, + 'entity_category': , 'entity_id': 'select.mock_door_lock_with_unbolt_operating_mode', 'has_entity_name': True, 'hidden_by': None, @@ -875,6 +889,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating mode', 'options': dict({ }), 'original_device_class': None, @@ -934,6 +949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -995,6 +1011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound volume', 'options': dict({ }), 'original_device_class': None, @@ -1055,6 +1072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clean mode', 'options': dict({ }), 'original_device_class': None, @@ -1119,6 +1137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clean mode', 'options': dict({ }), 'original_device_class': None, @@ -1184,6 +1203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup (bottom)', 'options': dict({ }), 'original_device_class': None, @@ -1245,6 +1265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup (top)', 'options': dict({ }), 'original_device_class': None, @@ -1306,6 +1327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -1367,6 +1389,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -1400,7 +1423,7 @@ 'state': 'previous', }) # --- -# name: test_selects[eve_thermo][select.eve_thermo_temperature_display_mode-entry] +# name: test_selects[eve_thermo_v4][select.eve_thermo_20ebp1701_temperature_display_mode-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1418,7 +1441,7 @@ 'disabled_by': None, 'domain': 'select', 'entity_category': , - 'entity_id': 'select.eve_thermo_temperature_display_mode', + 'entity_id': 'select.eve_thermo_20ebp1701_temperature_display_mode', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1426,6 +1449,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature display mode', 'options': dict({ }), 'original_device_class': None, @@ -1440,17 +1464,75 @@ 'unit_of_measurement': None, }) # --- -# name: test_selects[eve_thermo][select.eve_thermo_temperature_display_mode-state] +# name: test_selects[eve_thermo_v4][select.eve_thermo_20ebp1701_temperature_display_mode-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'Eve Thermo Temperature display mode', + 'friendly_name': 'Eve Thermo 20EBP1701 Temperature display mode', 'options': list([ 'Celsius', 'Fahrenheit', ]), }), 'context': , - 'entity_id': 'select.eve_thermo_temperature_display_mode', + 'entity_id': 'select.eve_thermo_20ebp1701_temperature_display_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Celsius', + }) +# --- +# name: test_selects[eve_thermo_v5][select.eve_thermo_20ecd1701_temperature_display_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'Celsius', + 'Fahrenheit', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': , + 'entity_id': 'select.eve_thermo_20ecd1701_temperature_display_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature display mode', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Temperature display mode', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'temperature_display_mode', + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-TrvTemperatureDisplayMode-516-0', + 'unit_of_measurement': None, + }) +# --- +# name: test_selects[eve_thermo_v5][select.eve_thermo_20ecd1701_temperature_display_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Eve Thermo 20ECD1701 Temperature display mode', + 'options': list([ + 'Celsius', + 'Fahrenheit', + ]), + }), + 'context': , + 'entity_id': 'select.eve_thermo_20ecd1701_temperature_display_mode', 'last_changed': , 'last_reported': , 'last_updated': , @@ -1484,6 +1566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lighting', 'options': dict({ }), 'original_device_class': None, @@ -1544,6 +1627,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -1604,6 +1688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1668,6 +1753,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button Press Delay', 'options': dict({ }), 'original_device_class': None, @@ -1744,6 +1830,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimming Speed', 'options': dict({ }), 'original_device_class': None, @@ -1825,6 +1912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED Color', 'options': dict({ }), 'original_device_class': None, @@ -1908,6 +1996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED Effect', 'options': dict({ }), 'original_device_class': None, @@ -1980,6 +2069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local Protection', 'options': dict({ }), 'original_device_class': None, @@ -2037,6 +2127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Local Timer', 'options': dict({ }), 'original_device_class': None, @@ -2096,6 +2187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup (Load Control)', 'options': dict({ }), 'original_device_class': None, @@ -2157,6 +2249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup (RGB Indicator)', 'options': dict({ }), 'original_device_class': None, @@ -2216,6 +2309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart Bulb Mode', 'options': dict({ }), 'original_device_class': None, @@ -2275,6 +2369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch Mode', 'options': dict({ }), 'original_device_class': None, @@ -2335,6 +2430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature level', 'options': dict({ }), 'original_device_class': None, @@ -2393,6 +2489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature display mode', 'options': dict({ }), 'original_device_class': None, @@ -2458,6 +2555,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power level (W)', 'options': dict({ }), 'original_device_class': None, @@ -2514,7 +2612,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'select', - 'entity_category': None, + 'entity_category': , 'entity_id': 'select.mock_lock_operating_mode', 'has_entity_name': True, 'hidden_by': None, @@ -2523,6 +2621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating mode', 'options': dict({ }), 'original_device_class': None, @@ -2582,6 +2681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound volume', 'options': dict({ }), 'original_device_class': None, @@ -2641,6 +2741,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature display mode', 'options': dict({ }), 'original_device_class': None, @@ -2700,6 +2801,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -2759,6 +2861,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimming Edge', 'options': dict({ }), 'original_device_class': None, @@ -2829,6 +2932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimming Speed', 'options': dict({ }), 'original_device_class': None, @@ -2910,6 +3014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED Color', 'options': dict({ }), 'original_device_class': None, @@ -2980,6 +3085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup (1)', 'options': dict({ }), 'original_device_class': None, @@ -3041,6 +3147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup (6)', 'options': dict({ }), 'original_device_class': None, @@ -3100,6 +3207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': None, @@ -3157,6 +3265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart Bulb Mode', 'options': dict({ }), 'original_device_class': None, @@ -3219,6 +3328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch Mode', 'options': dict({ }), 'original_device_class': None, @@ -3283,6 +3393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -3344,6 +3455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -3405,6 +3517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -3466,6 +3579,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -3527,6 +3641,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -3593,6 +3708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -3658,6 +3774,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature level', 'options': dict({ }), 'original_device_class': None, @@ -3718,6 +3835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'mode', 'options': dict({ }), 'original_device_class': None, @@ -3769,7 +3887,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'select', - 'entity_category': None, + 'entity_category': , 'entity_id': 'select.secuyou_smart_lock_operating_mode', 'has_entity_name': True, 'hidden_by': None, @@ -3778,6 +3896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating mode', 'options': dict({ }), 'original_device_class': None, @@ -3839,6 +3958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy management mode', 'options': dict({ }), 'original_device_class': None, @@ -3901,6 +4021,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -3960,6 +4081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Number of rinses', 'options': dict({ }), 'original_device_class': None, @@ -4019,6 +4141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spin speed', 'options': dict({ }), 'original_device_class': None, @@ -4079,6 +4202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature level', 'options': dict({ }), 'original_device_class': None, @@ -4138,6 +4262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -4199,6 +4324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy management mode', 'options': dict({ }), 'original_device_class': None, @@ -4261,6 +4387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, @@ -4323,6 +4450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clean mode', 'options': dict({ }), 'original_device_class': None, @@ -4386,6 +4514,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clean mode', 'options': dict({ }), 'original_device_class': None, @@ -4448,6 +4577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power-on behavior on startup', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_sensor.ambr b/tests/components/matter/snapshots/test_sensor.ambr index f9a2a1fdf08..a08dc90cd46 100644 --- a/tests/components/matter/snapshots/test_sensor.ambr +++ b/tests/components/matter/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activated carbon filter condition', 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': , @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ }), 'original_device_class': , @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HEPA filter condition', 'options': dict({ }), 'original_device_class': None, @@ -298,6 +303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -351,6 +357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ }), 'original_device_class': None, @@ -403,6 +410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone', 'options': dict({ }), 'original_device_class': , @@ -456,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -509,6 +518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -562,6 +572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -615,6 +626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -671,6 +683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -727,6 +740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -787,6 +801,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': , @@ -846,6 +861,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -899,6 +915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -952,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ }), 'original_device_class': None, @@ -1004,6 +1022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -1057,6 +1076,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -1110,6 +1130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -1163,6 +1184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1219,6 +1241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -1272,6 +1295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1323,6 +1347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -1373,9 +1398,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1432,6 +1458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1483,6 +1510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -1533,9 +1561,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1592,6 +1621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1645,6 +1675,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1696,6 +1727,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -1746,9 +1778,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1805,6 +1838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1858,6 +1892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1911,6 +1946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1967,6 +2003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2018,6 +2055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -2068,9 +2106,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -2127,6 +2166,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (3)', 'options': dict({ }), 'original_device_class': None, @@ -2178,6 +2218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (4)', 'options': dict({ }), 'original_device_class': None, @@ -2229,6 +2270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (5)', 'options': dict({ }), 'original_device_class': None, @@ -2280,6 +2322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2333,6 +2376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2389,6 +2433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -2448,6 +2493,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2501,6 +2547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2557,6 +2604,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2610,9 +2658,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -2669,6 +2718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2734,6 +2784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Appliance energy state', 'options': dict({ }), 'original_device_class': , @@ -2792,6 +2843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2845,9 +2897,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -2909,6 +2962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy optimization opt-out', 'options': dict({ }), 'original_device_class': , @@ -2966,6 +3020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3025,6 +3080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3084,6 +3140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to full charge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3143,6 +3200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3202,6 +3260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3256,6 +3315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating demand', 'options': dict({ }), 'original_device_class': None, @@ -3307,6 +3367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3363,6 +3424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3420,6 +3482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charge state', 'options': dict({ }), 'original_device_class': , @@ -3507,6 +3570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase', 'options': dict({ }), 'original_device_class': , @@ -3610,6 +3674,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -3690,6 +3755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -3750,6 +3816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to full charge', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3809,6 +3876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3866,6 +3934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charge state', 'options': dict({ }), 'original_device_class': , @@ -3942,6 +4011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -4022,6 +4092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -4082,6 +4153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4135,9 +4207,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -4194,6 +4267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (top)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4250,6 +4324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy (top)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4306,6 +4381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power (top)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4362,6 +4438,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage (top)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4418,6 +4495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4474,6 +4552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4530,6 +4609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4586,6 +4666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4642,6 +4723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4701,6 +4783,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -4760,6 +4843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4819,6 +4903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4876,6 +4961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target opening position', 'options': dict({ }), 'original_device_class': None, @@ -4904,7 +4990,7 @@ 'state': '100', }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_battery-entry] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -4919,7 +5005,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.eve_thermo_battery', + 'entity_id': 'sensor.eve_thermo_20ebp1701_battery', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -4927,6 +5013,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4941,23 +5028,23 @@ 'unit_of_measurement': '%', }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_battery-state] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'battery', - 'friendly_name': 'Eve Thermo Battery', + 'friendly_name': 'Eve Thermo 20EBP1701 Battery', 'state_class': , 'unit_of_measurement': '%', }), 'context': , - 'entity_id': 'sensor.eve_thermo_battery', + 'entity_id': 'sensor.eve_thermo_20ebp1701_battery', 'last_changed': , 'last_reported': , 'last_updated': , 'state': '100', }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_battery_voltage-entry] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery_voltage-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -4972,7 +5059,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.eve_thermo_battery_voltage', + 'entity_id': 'sensor.eve_thermo_20ebp1701_battery_voltage', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -4980,9 +5067,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -5000,23 +5088,23 @@ 'unit_of_measurement': , }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_battery_voltage-state] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_battery_voltage-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'voltage', - 'friendly_name': 'Eve Thermo Battery voltage', + 'friendly_name': 'Eve Thermo 20EBP1701 Battery voltage', 'state_class': , 'unit_of_measurement': , }), 'context': , - 'entity_id': 'sensor.eve_thermo_battery_voltage', + 'entity_id': 'sensor.eve_thermo_20ebp1701_battery_voltage', 'last_changed': , 'last_reported': , 'last_updated': , 'state': '3.05', }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_temperature-entry] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -5031,7 +5119,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.eve_thermo_temperature', + 'entity_id': 'sensor.eve_thermo_20ebp1701_temperature', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -5039,6 +5127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5056,23 +5145,23 @@ 'unit_of_measurement': , }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_temperature-state] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'temperature', - 'friendly_name': 'Eve Thermo Temperature', + 'friendly_name': 'Eve Thermo 20EBP1701 Temperature', 'state_class': , 'unit_of_measurement': , }), 'context': , - 'entity_id': 'sensor.eve_thermo_temperature', + 'entity_id': 'sensor.eve_thermo_20ebp1701_temperature', 'last_changed': , 'last_reported': , 'last_updated': , 'state': '21.0', }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_valve_position-entry] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_valve_position-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -5085,7 +5174,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.eve_thermo_valve_position', + 'entity_id': 'sensor.eve_thermo_20ebp1701_valve_position', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -5093,6 +5182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': None, @@ -5107,20 +5197,181 @@ 'unit_of_measurement': '%', }) # --- -# name: test_sensors[eve_thermo][sensor.eve_thermo_valve_position-state] +# name: test_sensors[eve_thermo_v4][sensor.eve_thermo_20ebp1701_valve_position-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'Eve Thermo Valve position', + 'friendly_name': 'Eve Thermo 20EBP1701 Valve position', 'unit_of_measurement': '%', }), 'context': , - 'entity_id': 'sensor.eve_thermo_valve_position', + 'entity_id': 'sensor.eve_thermo_20ebp1701_valve_position', 'last_changed': , 'last_reported': , 'last_updated': , 'state': '10', }) # --- +# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.eve_thermo_20ecd1701_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-0-PowerSource-47-12', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Eve Thermo 20ECD1701 Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.eve_thermo_20ecd1701_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100', + }) +# --- +# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.eve_thermo_20ecd1701_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-ThermostatLocalTemperature-513-0', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Eve Thermo 20ECD1701 Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.eve_thermo_20ecd1701_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '16.2', + }) +# --- +# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_valve_position-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.eve_thermo_20ecd1701_valve_position', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Valve position', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Valve position', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'valve_position', + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-EveThermoValvePosition-319486977-319422488', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[eve_thermo_v5][sensor.eve_thermo_20ecd1701_valve_position-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Eve Thermo 20ECD1701 Valve position', + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.eve_thermo_20ecd1701_valve_position', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- # name: test_sensors[eve_weather_sensor][sensor.eve_weather_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -5144,6 +5395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5197,9 +5449,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -5256,6 +5509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -5309,6 +5563,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5365,6 +5620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5426,6 +5682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather trend', 'options': dict({ }), 'original_device_class': , @@ -5483,6 +5740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activated carbon filter condition', 'options': dict({ }), 'original_device_class': None, @@ -5535,6 +5793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HEPA filter condition', 'options': dict({ }), 'original_device_class': None, @@ -5587,6 +5846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow', 'options': dict({ }), 'original_device_class': None, @@ -5639,6 +5899,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position', 'options': dict({ }), 'original_device_class': None, @@ -5690,6 +5951,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (1)', 'options': dict({ }), 'original_device_class': None, @@ -5741,6 +6003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (2)', 'options': dict({ }), 'original_device_class': None, @@ -5792,6 +6055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5845,9 +6109,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -5904,6 +6169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (1)', 'options': dict({ }), 'original_device_class': None, @@ -5955,6 +6221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (2)', 'options': dict({ }), 'original_device_class': None, @@ -6006,6 +6273,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (3)', 'options': dict({ }), 'original_device_class': None, @@ -6057,6 +6325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (4)', 'options': dict({ }), 'original_device_class': None, @@ -6108,6 +6377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (5)', 'options': dict({ }), 'original_device_class': None, @@ -6159,6 +6429,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (6)', 'options': dict({ }), 'original_device_class': None, @@ -6210,6 +6481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -6261,6 +6533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -6311,9 +6584,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -6370,6 +6644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -6423,6 +6698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6482,6 +6758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -6542,6 +6819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': , @@ -6601,6 +6879,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -6654,6 +6933,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -6707,6 +6987,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -6760,6 +7041,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6816,6 +7098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -6867,6 +7150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -6917,9 +7201,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -6976,6 +7261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (1)', 'options': dict({ }), 'original_device_class': None, @@ -7027,6 +7313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (2)', 'options': dict({ }), 'original_device_class': None, @@ -7078,6 +7365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (3)', 'options': dict({ }), 'original_device_class': None, @@ -7129,6 +7417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (4)', 'options': dict({ }), 'original_device_class': None, @@ -7180,6 +7469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (5)', 'options': dict({ }), 'original_device_class': None, @@ -7231,6 +7521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (6)', 'options': dict({ }), 'original_device_class': None, @@ -7282,6 +7573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (7)', 'options': dict({ }), 'original_device_class': None, @@ -7333,6 +7625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (8)', 'options': dict({ }), 'original_device_class': None, @@ -7384,6 +7677,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (9)', 'options': dict({ }), 'original_device_class': None, @@ -7435,6 +7729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7494,6 +7789,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (Config)', 'options': dict({ }), 'original_device_class': None, @@ -7545,6 +7841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (Down)', 'options': dict({ }), 'original_device_class': None, @@ -7596,6 +7893,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (Up)', 'options': dict({ }), 'original_device_class': None, @@ -7647,6 +7945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -7706,6 +8005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -7759,6 +8059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7818,6 +8119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7874,6 +8176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7937,6 +8240,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase', 'options': dict({ }), 'original_device_class': , @@ -7998,6 +8302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -8060,6 +8365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -8117,6 +8423,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -8170,6 +8477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8226,6 +8534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8280,6 +8589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated end time', 'options': dict({ }), 'original_device_class': , @@ -8336,6 +8646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -8398,6 +8709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -8455,6 +8767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door closed events', 'options': dict({ }), 'original_device_class': None, @@ -8506,6 +8819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door open events', 'options': dict({ }), 'original_device_class': None, @@ -8555,6 +8869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating demand', 'options': dict({ }), 'original_device_class': None, @@ -8606,6 +8921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8662,6 +8978,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8718,6 +9035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (Config)', 'options': dict({ }), 'original_device_class': None, @@ -8769,6 +9087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (Down)', 'options': dict({ }), 'original_device_class': None, @@ -8820,6 +9139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position (Up)', 'options': dict({ }), 'original_device_class': None, @@ -8875,6 +9195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase', 'options': dict({ }), 'original_device_class': , @@ -8935,6 +9256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -8991,6 +9313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature (2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9047,6 +9370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature (4)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9103,6 +9427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9166,6 +9491,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Control mode', 'options': dict({ }), 'original_device_class': , @@ -9225,6 +9551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow', 'options': dict({ }), 'original_device_class': None, @@ -9277,6 +9604,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9333,6 +9661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rotation speed', 'options': dict({ }), 'original_device_class': None, @@ -9385,6 +9714,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9418,6 +9748,63 @@ 'state': '60.0', }) # --- +# name: test_sensors[resideo_x2s_thermostat][sensor.x2s_smart_thermostat_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.x2s_smart_thermostat_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-0000000000000004-MatterNodeDevice-1-ThermostatLocalTemperature-513-0', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[resideo_x2s_thermostat][sensor.x2s_smart_thermostat_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'X2S Smart Thermostat Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.x2s_smart_thermostat_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '20.55', + }) +# --- # name: test_sensors[room_airconditioner][sensor.room_airconditioner_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -9441,6 +9828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9497,6 +9885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Effective current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9556,6 +9945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Effective voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9615,6 +10005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -9679,6 +10070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -9742,6 +10134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -9800,6 +10193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9865,6 +10259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Appliance energy state', 'options': dict({ }), 'original_device_class': , @@ -9923,6 +10318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Circuit capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9987,6 +10383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy optimization opt-out', 'options': dict({ }), 'original_device_class': , @@ -10061,6 +10458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault state', 'options': dict({ }), 'original_device_class': , @@ -10130,6 +10528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max charge current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10189,6 +10588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Min charge current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10248,6 +10648,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge', 'options': dict({ }), 'original_device_class': , @@ -10301,6 +10702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User max charge current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10364,6 +10766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase', 'options': dict({ }), 'original_device_class': , @@ -10420,6 +10823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Effective current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10479,6 +10883,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Effective voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10538,6 +10943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -10602,6 +11008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -10664,6 +11071,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -10721,6 +11129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10780,6 +11189,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current switch position', 'options': dict({ }), 'original_device_class': None, @@ -10831,6 +11241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10896,6 +11307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Appliance energy state', 'options': dict({ }), 'original_device_class': , @@ -10959,6 +11371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy optimization opt-out', 'options': dict({ }), 'original_device_class': , @@ -11016,6 +11429,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water level', 'options': dict({ }), 'original_device_class': None, @@ -11068,6 +11482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11127,6 +11542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Required heating energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -11186,6 +11602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank volume', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11242,6 +11659,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11301,6 +11719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -11352,6 +11771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery type', 'options': dict({ }), 'original_device_class': None, @@ -11402,9 +11822,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -11461,6 +11882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11520,6 +11942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -11579,6 +12002,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11638,6 +12062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11717,6 +12142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -11797,6 +12223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -11857,6 +12284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -11910,6 +12338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -11966,6 +12395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -12020,6 +12450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated end time', 'options': dict({ }), 'original_device_class': , @@ -12091,6 +12522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational error', 'options': dict({ }), 'original_device_class': , @@ -12171,6 +12603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational state', 'options': dict({ }), 'original_device_class': , @@ -12229,6 +12662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-close time', 'options': dict({ }), 'original_device_class': , @@ -12278,6 +12712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target opening position', 'options': dict({ }), 'original_device_class': None, @@ -12327,6 +12762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target opening position', 'options': dict({ }), 'original_device_class': None, @@ -12378,6 +12814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12434,6 +12871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12490,6 +12928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12546,6 +12985,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -12603,6 +13043,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charge state', 'options': dict({ }), 'original_device_class': , @@ -12659,9 +13100,10 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ - 'suggested_display_precision': 0, + 'suggested_display_precision': 2, }), 'sensor.private': dict({ 'suggested_unit_of_measurement': , diff --git a/tests/components/matter/snapshots/test_switch.ambr b/tests/components/matter/snapshots/test_switch.ambr index 94da1b87f93..565e3d77223 100644 --- a/tests/components/matter/snapshots/test_switch.ambr +++ b/tests/components/matter/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power (1)', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power (2)', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Privacy mode button', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Privacy mode button', 'options': dict({ }), 'original_device_class': None, @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch (bottom)', 'options': dict({ }), 'original_device_class': , @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch (top)', 'options': dict({ }), 'original_device_class': , @@ -410,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -459,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -487,7 +497,7 @@ 'state': 'off', }) # --- -# name: test_switches[eve_thermo][switch.eve_thermo_child_lock-entry] +# name: test_switches[eve_thermo_v4][switch.eve_thermo_20ebp1701_child_lock-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -500,7 +510,7 @@ 'disabled_by': None, 'domain': 'switch', 'entity_category': , - 'entity_id': 'switch.eve_thermo_child_lock', + 'entity_id': 'switch.eve_thermo_20ebp1701_child_lock', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -508,6 +518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -522,13 +533,62 @@ 'unit_of_measurement': None, }) # --- -# name: test_switches[eve_thermo][switch.eve_thermo_child_lock-state] +# name: test_switches[eve_thermo_v4][switch.eve_thermo_20ebp1701_child_lock-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'Eve Thermo Child lock', + 'friendly_name': 'Eve Thermo 20EBP1701 Child lock', }), 'context': , - 'entity_id': 'switch.eve_thermo_child_lock', + 'entity_id': 'switch.eve_thermo_20ebp1701_child_lock', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_switches[eve_thermo_v5][switch.eve_thermo_20ecd1701_child_lock-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.eve_thermo_20ecd1701_child_lock', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Child lock', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Child lock', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'child_lock', + 'unique_id': '00000000000004D2-000000000000000C-MatterNodeDevice-1-EveTrvChildLock-516-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_switches[eve_thermo_v5][switch.eve_thermo_20ecd1701_child_lock-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Eve Thermo 20ECD1701 Child lock', + }), + 'context': , + 'entity_id': 'switch.eve_thermo_20ecd1701_child_lock', 'last_changed': , 'last_reported': , 'last_updated': , @@ -556,6 +616,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -605,6 +666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch (Load Control)', 'options': dict({ }), 'original_device_class': , @@ -654,6 +716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -703,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -752,6 +816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Privacy mode button', 'options': dict({ }), 'original_device_class': None, @@ -800,6 +865,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -849,6 +915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power (3)', 'options': dict({ }), 'original_device_class': , @@ -898,6 +965,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power (4)', 'options': dict({ }), 'original_device_class': , @@ -947,6 +1015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -996,6 +1065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1045,6 +1115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Enable charging', 'options': dict({ }), 'original_device_class': None, @@ -1093,6 +1164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1142,6 +1214,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute', 'options': dict({ }), 'original_device_class': None, @@ -1190,6 +1263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1239,6 +1313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/matter/snapshots/test_vacuum.ambr b/tests/components/matter/snapshots/test_vacuum.ambr index f20b7701b6b..bfbe5982f0b 100644 --- a/tests/components/matter/snapshots/test_vacuum.ambr +++ b/tests/components/matter/snapshots/test_vacuum.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/snapshots/test_valve.ambr b/tests/components/matter/snapshots/test_valve.ambr index 6c178449083..c9f536ba58c 100644 --- a/tests/components/matter/snapshots/test_valve.ambr +++ b/tests/components/matter/snapshots/test_valve.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/matter/snapshots/test_water_heater.ambr b/tests/components/matter/snapshots/test_water_heater.ambr index 6dd483fb1d7..ca80c653a88 100644 --- a/tests/components/matter/snapshots/test_water_heater.ambr +++ b/tests/components/matter/snapshots/test_water_heater.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/matter/test_binary_sensor.py b/tests/components/matter/test_binary_sensor.py index 5b1a52c96c6..5362d6477ee 100644 --- a/tests/components/matter/test_binary_sensor.py +++ b/tests/components/matter/test_binary_sensor.py @@ -424,7 +424,9 @@ async def test_shutter_problem( ) -> None: """Test shutter problem.""" # Eve Shutter default state (ConfigStatus = 9) - state = hass.states.get("binary_sensor.eve_shutter_switch_20eci1701_problem") + state = hass.states.get( + "binary_sensor.eve_shutter_switch_20eci1701_configuration_status" + ) assert state assert state.state == "off" @@ -432,7 +434,9 @@ async def test_shutter_problem( set_node_attribute(matter_node, 1, 258, 7, 8) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("binary_sensor.eve_shutter_switch_20eci1701_problem") + state = hass.states.get( + "binary_sensor.eve_shutter_switch_20eci1701_configuration_status" + ) assert state assert state.state == "on" diff --git a/tests/components/matter/test_number.py b/tests/components/matter/test_number.py index bca68179f40..1790767dea5 100644 --- a/tests/components/matter/test_number.py +++ b/tests/components/matter/test_number.py @@ -236,6 +236,50 @@ async def test_microwave_oven( ) +@pytest.mark.parametrize("node_fixture", ["aqara_thermostat_w500"]) +async def test_thermostat_occupied_setback( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test thermostat occupied setback number entity.""" + + entity_id = "number.floor_heating_thermostat_occupied_setback" + + # Initial value comes from 1/513/52 with scale /10 (5 -> 0.5 °C) + state = hass.states.get(entity_id) + assert state + assert state.state == "0.5" + + # Update attribute to 30 (-> 3.0 °C) + set_node_attribute(matter_node, 1, 513, 52, 30) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get(entity_id) + assert state + assert state.state == "3.0" + + # Setting value to 2.0 °C writes 20 to OccupiedSetback (scale x10) + await hass.services.async_call( + "number", + "set_value", + { + "entity_id": entity_id, + "value": 2.0, + }, + blocking=True, + ) + + assert matter_client.write_attribute.call_count == 1 + assert matter_client.write_attribute.call_args == call( + node_id=matter_node.node_id, + attribute_path=create_attribute_path_from_attribute( + endpoint_id=1, + attribute=clusters.Thermostat.Attributes.OccupiedSetback, + ), + value=20, + ) + + @pytest.mark.parametrize("node_fixture", ["door_lock"]) async def test_lock_attributes( hass: HomeAssistant, diff --git a/tests/components/matter/test_sensor.py b/tests/components/matter/test_sensor.py index 9a5f01321fd..74b5bc705f2 100644 --- a/tests/components/matter/test_sensor.py +++ b/tests/components/matter/test_sensor.py @@ -201,7 +201,7 @@ async def test_battery_sensor_description( state = hass.states.get("sensor.smoke_sensor_battery_type") is None -@pytest.mark.parametrize("node_fixture", ["eve_thermo"]) +@pytest.mark.parametrize("node_fixture", ["eve_thermo_v4"]) async def test_eve_thermo_sensor( hass: HomeAssistant, matter_client: MagicMock, @@ -209,26 +209,26 @@ async def test_eve_thermo_sensor( ) -> None: """Test Eve Thermo.""" # Valve position - state = hass.states.get("sensor.eve_thermo_valve_position") + state = hass.states.get("sensor.eve_thermo_20ebp1701_valve_position") assert state assert state.state == "10" set_node_attribute(matter_node, 1, 319486977, 319422488, 0) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("sensor.eve_thermo_valve_position") + state = hass.states.get("sensor.eve_thermo_20ebp1701_valve_position") assert state assert state.state == "0" # LocalTemperature - state = hass.states.get("sensor.eve_thermo_temperature") + state = hass.states.get("sensor.eve_thermo_20ebp1701_temperature") assert state assert state.state == "21.0" set_node_attribute(matter_node, 1, 513, 0, 1800) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("sensor.eve_thermo_temperature") + state = hass.states.get("sensor.eve_thermo_20ebp1701_temperature") assert state assert state.state == "18.0" diff --git a/tests/components/matter/test_switch.py b/tests/components/matter/test_switch.py index ecb65e625d9..aed1a1c5cff 100644 --- a/tests/components/matter/test_switch.py +++ b/tests/components/matter/test_switch.py @@ -116,32 +116,32 @@ async def test_power_switch(hass: HomeAssistant, matter_node: MatterNode) -> Non assert state.attributes["friendly_name"] == "Room AirConditioner Power" -@pytest.mark.parametrize("node_fixture", ["eve_thermo"]) +@pytest.mark.parametrize("node_fixture", ["eve_thermo_v4"]) async def test_numeric_switch( hass: HomeAssistant, matter_client: MagicMock, matter_node: MatterNode, ) -> None: """Test numeric switch entity is discovered and working using an Eve Thermo fixture .""" - state = hass.states.get("switch.eve_thermo_child_lock") + state = hass.states.get("switch.eve_thermo_20ebp1701_child_lock") assert state assert state.state == "off" # name should be derived from description attribute - assert state.attributes["friendly_name"] == "Eve Thermo Child lock" + assert state.attributes["friendly_name"] == "Eve Thermo 20EBP1701 Child lock" # test attribute changes set_node_attribute(matter_node, 1, 516, 1, 1) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("switch.eve_thermo_child_lock") + state = hass.states.get("switch.eve_thermo_20ebp1701_child_lock") assert state.state == "on" set_node_attribute(matter_node, 1, 516, 1, 0) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("switch.eve_thermo_child_lock") + state = hass.states.get("switch.eve_thermo_20ebp1701_child_lock") assert state.state == "off" # test switch service await hass.services.async_call( "switch", "turn_on", - {"entity_id": "switch.eve_thermo_child_lock"}, + {"entity_id": "switch.eve_thermo_20ebp1701_child_lock"}, blocking=True, ) assert matter_client.write_attribute.call_count == 1 @@ -156,7 +156,7 @@ async def test_numeric_switch( await hass.services.async_call( "switch", "turn_off", - {"entity_id": "switch.eve_thermo_child_lock"}, + {"entity_id": "switch.eve_thermo_20ebp1701_child_lock"}, blocking=True, ) assert matter_client.write_attribute.call_count == 2 diff --git a/tests/components/mealie/snapshots/test_calendar.ambr b/tests/components/mealie/snapshots/test_calendar.ambr index ad1fdcc07bc..a23ffd963aa 100644 --- a/tests/components/mealie/snapshots/test_calendar.ambr +++ b/tests/components/mealie/snapshots/test_calendar.ambr @@ -154,6 +154,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Breakfast', 'options': dict({ }), 'original_device_class': None, @@ -208,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dessert', 'options': dict({ }), 'original_device_class': None, @@ -262,6 +264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dinner', 'options': dict({ }), 'original_device_class': None, @@ -316,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Drink', 'options': dict({ }), 'original_device_class': None, @@ -370,6 +374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lunch', 'options': dict({ }), 'original_device_class': None, @@ -424,6 +429,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side', 'options': dict({ }), 'original_device_class': None, @@ -478,6 +484,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Snack', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/mealie/snapshots/test_sensor.ambr b/tests/components/mealie/snapshots/test_sensor.ambr index 9dea508df39..0a2277dc04f 100644 --- a/tests/components/mealie/snapshots/test_sensor.ambr +++ b/tests/components/mealie/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Categories', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Recipes', 'options': dict({ }), 'original_device_class': None, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tags', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tools', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Users', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/mealie/snapshots/test_services.ambr b/tests/components/mealie/snapshots/test_services.ambr index 30f70bc9273..2591741c8d2 100644 --- a/tests/components/mealie/snapshots/test_services.ambr +++ b/tests/components/mealie/snapshots/test_services.ambr @@ -1647,80 +1647,135 @@ 'image': 'SuPW', 'ingredients': list([ dict({ + 'display': '1 130g dark couverture chocolate (min. 55% cocoa content)', + 'food': None, 'is_food': None, 'note': '130g dark couverture chocolate (min. 55% cocoa content)', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'a3adfe78-d157-44d8-98be-9c133e45bb4e', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 1 Vanilla Pod', + 'food': None, 'is_food': True, 'note': '1 Vanilla Pod', + 'original_text': None, 'quantity': 1.0, 'reference_id': '41d234d7-c040-48f9-91e6-f4636aebb77b', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 150g softened butter', + 'food': None, 'is_food': None, 'note': '150g softened butter', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'f6ce06bf-8b02-43e6-8316-0dc3fb0da0fc', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 100g Icing sugar', + 'food': None, 'is_food': True, 'note': '100g Icing sugar', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'f7fcd86e-b04b-4e07-b69c-513925811491', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 6 Eggs', + 'food': None, 'is_food': True, 'note': '6 Eggs', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'a831fbc3-e2f5-452e-a745-450be8b4a130', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 100g Castor sugar', + 'food': None, 'is_food': True, 'note': '100g Castor sugar', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'b5ee4bdc-0047-4de7-968b-f3360bbcb31e', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 140g Plain wheat flour', + 'food': None, 'is_food': True, 'note': '140g Plain wheat flour', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'a67db09d-429c-4e77-919d-cfed3da675ad', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 200g apricot jam', + 'food': None, 'is_food': True, 'note': '200g apricot jam', + 'original_text': None, 'quantity': 1.0, 'reference_id': '55479752-c062-4b25-aae3-2b210999d7b9', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 200g castor sugar', + 'food': None, 'is_food': True, 'note': '200g castor sugar', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'ff9cd404-24ec-4d38-b0aa-0120ce1df679', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 150g dark couverture chocolate (min. 55% cocoa content)', + 'food': None, 'is_food': True, 'note': '150g dark couverture chocolate (min. 55% cocoa content)', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'c7fca92e-971e-4728-a227-8b04783583ed', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 Unsweetend whipped cream to garnish', + 'food': None, 'is_food': True, 'note': 'Unsweetend whipped cream to garnish', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'ef023f23-7816-4871-87f6-4d29f9a283f7', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), ]), @@ -2223,80 +2278,135 @@ 'image': 'SuPW', 'ingredients': list([ dict({ + 'display': '1 130g dark couverture chocolate (min. 55% cocoa content)', + 'food': None, 'is_food': None, 'note': '130g dark couverture chocolate (min. 55% cocoa content)', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'a3adfe78-d157-44d8-98be-9c133e45bb4e', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 1 Vanilla Pod', + 'food': None, 'is_food': True, 'note': '1 Vanilla Pod', + 'original_text': None, 'quantity': 1.0, 'reference_id': '41d234d7-c040-48f9-91e6-f4636aebb77b', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 150g softened butter', + 'food': None, 'is_food': None, 'note': '150g softened butter', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'f6ce06bf-8b02-43e6-8316-0dc3fb0da0fc', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 100g Icing sugar', + 'food': None, 'is_food': True, 'note': '100g Icing sugar', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'f7fcd86e-b04b-4e07-b69c-513925811491', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 6 Eggs', + 'food': None, 'is_food': True, 'note': '6 Eggs', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'a831fbc3-e2f5-452e-a745-450be8b4a130', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 100g Castor sugar', + 'food': None, 'is_food': True, 'note': '100g Castor sugar', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'b5ee4bdc-0047-4de7-968b-f3360bbcb31e', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 140g Plain wheat flour', + 'food': None, 'is_food': True, 'note': '140g Plain wheat flour', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'a67db09d-429c-4e77-919d-cfed3da675ad', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 200g apricot jam', + 'food': None, 'is_food': True, 'note': '200g apricot jam', + 'original_text': None, 'quantity': 1.0, 'reference_id': '55479752-c062-4b25-aae3-2b210999d7b9', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 200g castor sugar', + 'food': None, 'is_food': True, 'note': '200g castor sugar', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'ff9cd404-24ec-4d38-b0aa-0120ce1df679', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 150g dark couverture chocolate (min. 55% cocoa content)', + 'food': None, 'is_food': True, 'note': '150g dark couverture chocolate (min. 55% cocoa content)', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'c7fca92e-971e-4728-a227-8b04783583ed', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), dict({ + 'display': '1 Unsweetend whipped cream to garnish', + 'food': None, 'is_food': True, 'note': 'Unsweetend whipped cream to garnish', + 'original_text': None, 'quantity': 1.0, 'reference_id': 'ef023f23-7816-4871-87f6-4d29f9a283f7', + 'referenced_recipe': None, + 'title': None, 'unit': None, }), ]), diff --git a/tests/components/mealie/snapshots/test_todo.ambr b/tests/components/mealie/snapshots/test_todo.ambr index 26cfb1ced68..74b0e22cb7f 100644 --- a/tests/components/mealie/snapshots/test_todo.ambr +++ b/tests/components/mealie/snapshots/test_todo.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Special groceries', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supermarket', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/mealie/test_config_flow.py b/tests/components/mealie/test_config_flow.py index d4ff9ec8e73..0f7ea6a4d50 100644 --- a/tests/components/mealie/test_config_flow.py +++ b/tests/components/mealie/test_config_flow.py @@ -103,7 +103,7 @@ async def test_ingress_host( result = await hass.config_entries.flow.async_configure( result["flow_id"], { - CONF_HOST: "http://homeassistant/hassio/ingress/db21ed7f_mealie", + CONF_HOST: "http://homeassistant/app/db21ed7f_mealie", CONF_API_TOKEN: "token", }, ) diff --git a/tests/components/meater/snapshots/test_sensor.ambr b/tests/components/meater/snapshots/test_sensor.ambr index f66bc854e2c..449bc014f4a 100644 --- a/tests/components/meater/snapshots/test_sensor.ambr +++ b/tests/components/meater/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -88,6 +89,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cook state', 'options': dict({ }), 'original_device_class': , @@ -148,6 +150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking', 'options': dict({ }), 'original_device_class': None, @@ -198,6 +201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -254,6 +258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -310,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -364,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time elapsed', 'options': dict({ }), 'original_device_class': , @@ -413,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time remaining', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/media_player/test_device_condition.py b/tests/components/media_player/test_device_condition.py index 78d30e2ca6e..531e412670b 100644 --- a/tests/components/media_player/test_device_condition.py +++ b/tests/components/media_player/test_device_condition.py @@ -23,11 +23,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/media_player/test_device_trigger.py b/tests/components/media_player/test_device_trigger.py index e82f1cd3612..7618d0a474b 100644 --- a/tests/components/media_player/test_device_trigger.py +++ b/tests/components/media_player/test_device_trigger.py @@ -31,11 +31,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/media_player/test_trigger.py b/tests/components/media_player/test_trigger.py index c8ba0129e02..11d9eefb844 100644 --- a/tests/components/media_player/test_trigger.py +++ b/tests/components/media_player/test_trigger.py @@ -1,8 +1,6 @@ """Test media player trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -20,21 +18,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_media_players(hass: HomeAssistant) -> list[str]: """Create multiple media player entities associated with different targets.""" @@ -60,7 +43,7 @@ async def test_media_player_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("media_player"), @@ -92,7 +75,7 @@ async def test_media_player_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the media player state trigger fires when any media player state changes to a specific state.""" other_entity_ids = set(target_media_players) - {entity_id} @@ -121,7 +104,7 @@ async def test_media_player_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("media_player"), @@ -153,7 +136,7 @@ async def test_media_player_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the media player state trigger fires when the first media player changes to a specific state.""" other_entity_ids = set(target_media_players) - {entity_id} @@ -181,7 +164,7 @@ async def test_media_player_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("media_player"), @@ -213,7 +196,7 @@ async def test_media_player_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the media player state trigger fires when the last media player changes to a specific state.""" other_entity_ids = set(target_media_players) - {entity_id} diff --git a/tests/components/melcloud/test_atw_zone_sensor.py b/tests/components/melcloud/test_atw_zone_sensor.py index 5ffb6dd7ff5..0f947eefdaf 100644 --- a/tests/components/melcloud/test_atw_zone_sensor.py +++ b/tests/components/melcloud/test_atw_zone_sensor.py @@ -1,6 +1,6 @@ """Test the MELCloud ATW zone sensor.""" -from unittest.mock import patch +from unittest.mock import MagicMock, patch import pytest @@ -8,32 +8,45 @@ from homeassistant.components.melcloud.sensor import ATW_ZONE_SENSORS, AtwZoneSe @pytest.fixture -def mock_device(): - """Mock MELCloud device.""" - with patch("homeassistant.components.melcloud.MelCloudDevice") as mock: - mock.name = "name" - mock.device.serial = 1234 - mock.device.mac = "11:11:11:11:11:11" +def mock_coordinator(): + """Mock MELCloud coordinator.""" + with patch( + "homeassistant.components.melcloud.coordinator.MelCloudDeviceUpdateCoordinator" + ) as mock: yield mock +@pytest.fixture +def mock_device(mock_coordinator): + """Mock MELCloud device.""" + mock = MagicMock() + mock.name = "name" + mock.device.serial = 1234 + mock.device.mac = "11:11:11:11:11:11" + mock.zone_device_info.return_value = {} + mock.coordinator = mock_coordinator + return mock + + @pytest.fixture def mock_zone_1(): """Mock zone 1.""" - with patch("pymelcloud.atw_device.Zone") as mock: - mock.zone_index = 1 - yield mock + mock = MagicMock() + mock.zone_index = 1 + return mock @pytest.fixture def mock_zone_2(): """Mock zone 2.""" - with patch("pymelcloud.atw_device.Zone") as mock: - mock.zone_index = 2 - yield mock + mock = MagicMock() + mock.zone_index = 2 + return mock -def test_zone_unique_ids(mock_device, mock_zone_1, mock_zone_2) -> None: +def test_zone_unique_ids( + mock_coordinator, mock_device, mock_zone_1, mock_zone_2 +) -> None: """Test unique id generation correctness.""" sensor_1 = AtwZoneSensor( mock_device, diff --git a/tests/components/melcloud/test_config_flow.py b/tests/components/melcloud/test_config_flow.py index 3f6e42ac264..618d132fb23 100644 --- a/tests/components/melcloud/test_config_flow.py +++ b/tests/components/melcloud/test_config_flow.py @@ -75,7 +75,11 @@ async def test_form(hass: HomeAssistant, mock_login, mock_get_devices) -> None: @pytest.mark.parametrize( ("error", "reason"), - [(ClientError(), "cannot_connect"), (TimeoutError(), "cannot_connect")], + [ + (ClientError(), "cannot_connect"), + (TimeoutError(), "cannot_connect"), + (AttributeError(), "invalid_auth"), + ], ) async def test_form_errors( hass: HomeAssistant, mock_login, mock_get_devices, error, reason diff --git a/tests/components/meteo_france/snapshots/test_sensor.ambr b/tests/components/meteo_france/snapshots/test_sensor.ambr index e8f5ce87553..d95d398c56a 100644 --- a/tests/components/meteo_france/snapshots/test_sensor.ambr +++ b/tests/components/meteo_france/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': '32 Weather alert', 'options': dict({ }), 'original_device_class': None, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Cloud cover', 'options': dict({ }), 'original_device_class': None, @@ -127,6 +129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Daily original condition', 'options': dict({ }), 'original_device_class': None, @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Daily precipitation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Freeze chance', 'options': dict({ }), 'original_device_class': None, @@ -283,6 +288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Humidity', 'options': dict({ }), 'original_device_class': , @@ -335,6 +341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Original condition', 'options': dict({ }), 'original_device_class': None, @@ -386,6 +393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -441,6 +449,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Rain chance', 'options': dict({ }), 'original_device_class': None, @@ -492,6 +501,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Snow chance', 'options': dict({ }), 'original_device_class': None, @@ -545,6 +555,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -600,6 +611,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz UV', 'options': dict({ }), 'original_device_class': None, @@ -653,6 +665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Wind gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -711,6 +724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -766,6 +780,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meudon Next rain', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/meteo_france/snapshots/test_weather.ambr b/tests/components/meteo_france/snapshots/test_weather.ambr index 4fdc22cd427..62e85e5cf55 100644 --- a/tests/components/meteo_france/snapshots/test_weather.ambr +++ b/tests/components/meteo_france/snapshots/test_weather.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'La Clusaz', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/meteo_lt/snapshots/test_weather.ambr b/tests/components/meteo_lt/snapshots/test_weather.ambr index a3e5e911530..d099fd1d66e 100644 --- a/tests/components/meteo_lt/snapshots/test_weather.ambr +++ b/tests/components/meteo_lt/snapshots/test_weather.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/mfi/test_sensor.py b/tests/components/mfi/test_sensor.py index 8c21fa9cb36..b756fb44a72 100644 --- a/tests/components/mfi/test_sensor.py +++ b/tests/components/mfi/test_sensor.py @@ -34,7 +34,7 @@ async def test_setup_missing_config(hass: HomeAssistant) -> None: """Test setup with missing configuration.""" with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: config = {"sensor": {"platform": "mfi"}} - assert await async_setup_component(hass, "sensor", config) + assert await async_setup_component(hass, COMPONENT.DOMAIN, config) assert not mock_client.called @@ -42,14 +42,14 @@ async def test_setup_failed_login(hass: HomeAssistant) -> None: """Test setup with login failure.""" with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: mock_client.side_effect = FailedToLogin - assert not PLATFORM.setup_platform(hass, GOOD_CONFIG, None) + assert not PLATFORM.setup_platform(hass, GOOD_CONFIG[COMPONENT.DOMAIN], None) async def test_setup_failed_connect(hass: HomeAssistant) -> None: """Test setup with connection failure.""" with mock.patch("homeassistant.components.mfi.sensor.MFiClient") as mock_client: mock_client.side_effect = requests.exceptions.ConnectionError - assert not PLATFORM.setup_platform(hass, GOOD_CONFIG, None) + assert not PLATFORM.setup_platform(hass, GOOD_CONFIG[COMPONENT.DOMAIN], None) async def test_setup_minimum(hass: HomeAssistant) -> None: @@ -111,7 +111,7 @@ async def test_setup_adds_proper_devices(hass: HomeAssistant) -> None: await hass.async_block_till_done() for ident, port in ports.items(): if ident != "bad": - mock_sensor.assert_any_call(port, hass) + mock_sensor.assert_any_call(port) assert mock.call(ports["bad"], hass) not in mock_sensor.mock_calls @@ -124,7 +124,7 @@ def port_fixture() -> mock.MagicMock: @pytest.fixture(name="sensor") def sensor_fixture(hass: HomeAssistant, port: mock.MagicMock) -> mfi.MfiSensor: """Sensor fixture.""" - sensor = mfi.MfiSensor(port, hass) + sensor = mfi.MfiSensor(port) sensor.hass = hass return sensor diff --git a/tests/components/miele/snapshots/test_binary_sensor.ambr b/tests/components/miele/snapshots/test_binary_sensor.ambr index 9a3de2ddd49..42249e9c13f 100644 --- a/tests/components/miele/snapshots/test_binary_sensor.ambr +++ b/tests/components/miele/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -311,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -359,6 +366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -408,6 +416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -457,6 +466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -505,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -553,6 +564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -602,6 +614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -650,6 +663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -699,6 +713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -748,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -796,6 +812,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -844,6 +861,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -893,6 +911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -941,6 +960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -990,6 +1010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -1039,6 +1060,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1087,6 +1109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -1135,6 +1158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -1184,6 +1208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -1232,6 +1257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -1281,6 +1307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -1330,6 +1357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1378,6 +1406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -1426,6 +1455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -1475,6 +1505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -1523,6 +1554,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -1572,6 +1604,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -1621,6 +1654,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1669,6 +1703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -1717,6 +1752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -1765,6 +1801,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -1814,6 +1851,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -1863,6 +1901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1911,6 +1950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -1959,6 +1999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -2008,6 +2049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -2056,6 +2098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -2105,6 +2148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -2154,6 +2198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2202,6 +2247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -2250,6 +2296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -2299,6 +2346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -2347,6 +2395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -2396,6 +2445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -2445,6 +2495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2493,6 +2544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, @@ -2541,6 +2593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -2590,6 +2643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mobile start', 'options': dict({ }), 'original_device_class': None, @@ -2638,6 +2692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Notification active', 'options': dict({ }), 'original_device_class': , @@ -2687,6 +2742,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -2736,6 +2792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2784,6 +2841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart grid', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_button.ambr b/tests/components/miele/snapshots/test_button.ambr index e4eb80587c9..01cb10d6845 100644 --- a/tests/components/miele/snapshots/test_button.ambr +++ b/tests/components/miele/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_climate.ambr b/tests/components/miele/snapshots/test_climate.ambr index 1349cf9b2ad..e1216d5e479 100644 --- a/tests/components/miele/snapshots/test_climate.ambr +++ b/tests/components/miele/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -155,6 +157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -219,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -283,6 +287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer', 'options': dict({ }), 'original_device_class': None, @@ -347,6 +352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer', 'options': dict({ }), 'original_device_class': None, @@ -411,6 +417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Refrigerator', 'options': dict({ }), 'original_device_class': None, @@ -475,6 +482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Refrigerator', 'options': dict({ }), 'original_device_class': None, @@ -539,6 +547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 3', 'options': dict({ }), 'original_device_class': None, @@ -603,6 +612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 3', 'options': dict({ }), 'original_device_class': None, @@ -667,6 +677,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer', 'options': dict({ }), 'original_device_class': None, @@ -731,6 +742,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer', 'options': dict({ }), 'original_device_class': None, @@ -795,6 +807,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Refrigerator', 'options': dict({ }), 'original_device_class': None, @@ -859,6 +872,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Refrigerator', 'options': dict({ }), 'original_device_class': None, @@ -923,6 +937,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 3', 'options': dict({ }), 'original_device_class': None, @@ -987,6 +1002,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 3', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_fan.ambr b/tests/components/miele/snapshots/test_fan.ambr index 8e5b3afd072..ec844da9274 100644 --- a/tests/components/miele/snapshots/test_fan.ambr +++ b/tests/components/miele/snapshots/test_fan.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan', 'options': dict({ }), 'original_device_class': None, @@ -122,6 +124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan', 'options': dict({ }), 'original_device_class': None, @@ -177,6 +180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_light.ambr b/tests/components/miele/snapshots/test_light.ambr index 243536fc997..b3bb243fbaa 100644 --- a/tests/components/miele/snapshots/test_light.ambr +++ b/tests/components/miele/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient light', 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -138,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -195,6 +198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient light', 'options': dict({ }), 'original_device_class': None, @@ -252,6 +256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -309,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_select.ambr b/tests/components/miele/snapshots/test_select.ambr index 941ed652612..64560b33a5c 100644 --- a/tests/components/miele/snapshots/test_select.ambr +++ b/tests/components/miele/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_sensor.ambr b/tests/components/miele/snapshots/test_sensor.ambr index 53929f59848..a14c0c71362 100644 --- a/tests/components/miele/snapshots/test_sensor.ambr +++ b/tests/components/miele/snapshots/test_sensor.ambr @@ -42,6 +42,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -147,6 +148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program', 'options': dict({ }), 'original_device_class': , @@ -245,6 +247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program phase', 'options': dict({ }), 'original_device_class': , @@ -316,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program type', 'options': dict({ }), 'original_device_class': , @@ -372,6 +376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -421,6 +426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -470,6 +476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -519,6 +526,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -568,6 +576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -617,6 +626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -688,6 +698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -781,6 +792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -877,6 +889,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 1', 'options': dict({ }), 'original_device_class': , @@ -975,6 +988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 1', 'options': dict({ }), 'original_device_class': , @@ -1073,6 +1087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 2', 'options': dict({ }), 'original_device_class': , @@ -1171,6 +1186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 2', 'options': dict({ }), 'original_device_class': , @@ -1269,6 +1285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 3', 'options': dict({ }), 'original_device_class': , @@ -1367,6 +1384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 3', 'options': dict({ }), 'original_device_class': , @@ -1465,6 +1483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 4', 'options': dict({ }), 'original_device_class': , @@ -1563,6 +1582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 4', 'options': dict({ }), 'original_device_class': , @@ -1661,6 +1681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 5', 'options': dict({ }), 'original_device_class': , @@ -1756,6 +1777,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1827,6 +1849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -1876,6 +1899,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -1925,6 +1949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -1974,6 +1999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -2023,6 +2049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -2072,6 +2099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -2143,6 +2171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2236,6 +2265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2309,6 +2339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2365,6 +2396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2421,6 +2453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature zone 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2475,6 +2508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -2524,6 +2558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -2573,6 +2608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -2622,6 +2658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -2671,6 +2708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -2720,6 +2758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -2791,6 +2830,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2887,6 +2927,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 1', 'options': dict({ }), 'original_device_class': , @@ -2985,6 +3026,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 2', 'options': dict({ }), 'original_device_class': , @@ -3083,6 +3125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 3', 'options': dict({ }), 'original_device_class': , @@ -3181,6 +3224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 4', 'options': dict({ }), 'original_device_class': , @@ -3279,6 +3323,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plate 5', 'options': dict({ }), 'original_device_class': , @@ -3352,6 +3397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -3401,6 +3447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -3450,6 +3497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -3499,6 +3547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -3548,6 +3597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -3597,6 +3647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -3668,6 +3719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3741,6 +3793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3817,6 +3870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3888,6 +3942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -3937,6 +3992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -3986,6 +4042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -4035,6 +4092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -4106,6 +4164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -4179,6 +4238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4233,6 +4293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elapsed time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4286,6 +4347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Finish', 'options': dict({ }), 'original_device_class': , @@ -4494,6 +4556,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program', 'options': dict({ }), 'original_device_class': , @@ -4710,6 +4773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program phase', 'options': dict({ }), 'original_device_class': , @@ -4775,6 +4839,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program type', 'options': dict({ }), 'original_device_class': , @@ -4831,6 +4896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4884,6 +4950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': , @@ -4933,6 +5000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start in', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4991,6 +5059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5047,6 +5116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5123,6 +5193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -5196,6 +5267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5272,6 +5344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -5343,6 +5416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elapsed time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5398,6 +5472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5452,6 +5527,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy forecast', 'options': dict({ }), 'original_device_class': None, @@ -5501,6 +5577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Finish', 'options': dict({ }), 'original_device_class': , @@ -5598,6 +5675,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program', 'options': dict({ }), 'original_device_class': , @@ -5718,6 +5796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program phase', 'options': dict({ }), 'original_device_class': , @@ -5798,6 +5877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program type', 'options': dict({ }), 'original_device_class': , @@ -5854,6 +5934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5907,6 +5988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spin speed', 'options': dict({ }), 'original_device_class': None, @@ -5956,6 +6038,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': , @@ -6005,6 +6088,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start in', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6063,6 +6147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6117,6 +6202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -6166,6 +6252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -6217,6 +6304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6271,6 +6359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water forecast', 'options': dict({ }), 'original_device_class': None, @@ -6342,6 +6431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -6415,6 +6505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6491,6 +6582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -6562,6 +6654,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -6611,6 +6704,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -6660,6 +6754,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -6709,6 +6804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -6780,6 +6876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -6853,6 +6950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6907,6 +7005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elapsed time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6960,6 +7059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Finish', 'options': dict({ }), 'original_device_class': , @@ -7168,6 +7268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program', 'options': dict({ }), 'original_device_class': , @@ -7384,6 +7485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program phase', 'options': dict({ }), 'original_device_class': , @@ -7449,6 +7551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program type', 'options': dict({ }), 'original_device_class': , @@ -7505,6 +7608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7558,6 +7662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': , @@ -7607,6 +7712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start in', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7665,6 +7771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7721,6 +7828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7797,6 +7905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -7870,6 +7979,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7946,6 +8056,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -8017,6 +8128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elapsed time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8072,6 +8184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8126,6 +8239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy forecast', 'options': dict({ }), 'original_device_class': None, @@ -8175,6 +8289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Finish', 'options': dict({ }), 'original_device_class': , @@ -8272,6 +8387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program', 'options': dict({ }), 'original_device_class': , @@ -8392,6 +8508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program phase', 'options': dict({ }), 'original_device_class': , @@ -8472,6 +8589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program type', 'options': dict({ }), 'original_device_class': , @@ -8528,6 +8646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8581,6 +8700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spin speed', 'options': dict({ }), 'original_device_class': None, @@ -8630,6 +8750,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': , @@ -8679,6 +8800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start in', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8737,6 +8859,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8791,6 +8914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -8840,6 +8964,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -8891,6 +9016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8945,6 +9071,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water forecast', 'options': dict({ }), 'original_device_class': None, @@ -8994,6 +9121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse aid level', 'options': dict({ }), 'original_device_class': None, @@ -9043,6 +9171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt level', 'options': dict({ }), 'original_device_class': None, @@ -9092,6 +9221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -9141,6 +9271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 1 level', 'options': dict({ }), 'original_device_class': None, @@ -9190,6 +9321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -9239,6 +9371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TwinDos 2 level', 'options': dict({ }), 'original_device_class': None, @@ -9310,6 +9443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -9381,6 +9515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -9431,6 +9566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elapsed time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9484,6 +9620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Finish', 'options': dict({ }), 'original_device_class': , @@ -9541,6 +9678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program', 'options': dict({ }), 'original_device_class': , @@ -9605,6 +9743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Program type', 'options': dict({ }), 'original_device_class': , @@ -9661,6 +9800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9714,6 +9854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/miele/snapshots/test_switch.ambr b/tests/components/miele/snapshots/test_switch.ambr index 769b08271a5..7af7fc9f9f0 100644 --- a/tests/components/miele/snapshots/test_switch.ambr +++ b/tests/components/miele/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Superfreezing', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supercooling', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Superfreezing', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supercooling', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/miele/snapshots/test_vacuum.ambr b/tests/components/miele/snapshots/test_vacuum.ambr index 3b808ad9cd2..5113273b2f3 100644 --- a/tests/components/miele/snapshots/test_vacuum.ambr +++ b/tests/components/miele/snapshots/test_vacuum.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -87,6 +88,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/mill/test_climate.py b/tests/components/mill/test_climate.py new file mode 100644 index 00000000000..0e72511bc11 --- /dev/null +++ b/tests/components/mill/test_climate.py @@ -0,0 +1,572 @@ +"""Tests for Mill climate.""" + +import contextlib +from contextlib import nullcontext +from unittest.mock import MagicMock, call, patch + +from mill import Heater +from mill_local import OperationMode +import pytest + +from homeassistant.components import mill +from homeassistant.components.climate import ( + ATTR_HVAC_MODE, + DOMAIN as CLIMATE_DOMAIN, + SERVICE_SET_HVAC_MODE, + SERVICE_SET_TEMPERATURE, + HVACMode, +) +from homeassistant.components.mill.const import DOMAIN +from homeassistant.components.recorder import Recorder +from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, Platform +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError + +from tests.common import MockConfigEntry + +HEATER_ID = "dev_id" +HEATER_NAME = "heater_name" +ENTITY_CLIMATE = f"climate.{HEATER_NAME}" + +TEST_SET_TEMPERATURE = 25 +TEST_AMBIENT_TEMPERATURE = 20 + +NULL_EFFECT = nullcontext() + +## MILL AND LOCAL MILL FIXTURES + + +@pytest.fixture +async def mock_mill(): + """Mock the mill.Mill object. + + It is imported and initialized only in /homeassistant/components/mill/__init__.py + """ + + with ( + patch( + "homeassistant.components.mill.Mill", + autospec=True, + ) as mock_mill_class, + ): + mill = mock_mill_class.return_value + mill.connect.return_value = True + mill.fetch_heater_and_sensor_data.return_value = {} + mill.fetch_historic_energy_usage.return_value = {} + yield mill + + +@pytest.fixture +async def mock_mill_local(): + """Mock the mill_local.Mill object.""" + + with ( + patch( + "homeassistant.components.mill.MillLocal", + autospec=True, + ) as mock_mill_local_class, + ): + milllocal = mock_mill_local_class.return_value + milllocal.url = "http://dummy.url" + milllocal.name = HEATER_NAME + milllocal.mac_address = "dead:beef" + milllocal.version = "0x210927" + milllocal.connect.return_value = { + "name": milllocal.name, + "mac_address": milllocal.mac_address, + "version": milllocal.version, + "operation_key": "", + "status": "ok", + } + status = { + "ambient_temperature": TEST_AMBIENT_TEMPERATURE, + "set_temperature": TEST_AMBIENT_TEMPERATURE, + "current_power": 0, + "control_signal": 0, + "raw_ambient_temperature": TEST_AMBIENT_TEMPERATURE, + "operation_mode": OperationMode.OFF.value, + } + milllocal.fetch_heater_and_sensor_data.return_value = status + milllocal._status = status + yield milllocal + + +## CLOUD HEATER INTEGRATION + + +@pytest.fixture +async def cloud_heater(hass: HomeAssistant, mock_mill: MagicMock) -> Heater: + """Load Mill integration and creates one cloud heater.""" + + heater = Heater( + name=HEATER_NAME, + device_id=HEATER_ID, + available=True, + is_heating=False, + power_status=False, + current_temp=float(TEST_AMBIENT_TEMPERATURE), + set_temp=float(TEST_AMBIENT_TEMPERATURE), + ) + + devices = {HEATER_ID: heater} + + mock_mill.fetch_heater_and_sensor_data.return_value = devices + mock_mill.devices = devices + + config_entry = MockConfigEntry( + domain=DOMAIN, + data={ + mill.CONF_USERNAME: "user", + mill.CONF_PASSWORD: "pswd", + mill.CONNECTION_TYPE: mill.CLOUD, + }, + ) + config_entry.add_to_hass(hass) + + # We just need to load the climate component. + with patch("homeassistant.components.mill.PLATFORMS", [Platform.CLIMATE]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + + await hass.async_block_till_done() + + return heater + + +@pytest.fixture +async def cloud_heater_set_temp(mock_mill: MagicMock, cloud_heater: MagicMock): + """Gets mock for the cloud heater `set_heater_temp` method.""" + return mock_mill.set_heater_temp + + +@pytest.fixture +async def cloud_heater_control(mock_mill: MagicMock, cloud_heater: MagicMock): + """Gets mock for the cloud heater `heater_control` method.""" + return mock_mill.heater_control + + +@pytest.fixture +async def functional_cloud_heater( + cloud_heater: MagicMock, + cloud_heater_set_temp: MagicMock, + cloud_heater_control: MagicMock, +) -> Heater: + """Make sure the cloud heater is "functional". + + This will create a pseudo-functional cloud heater, + meaning that function calls will edit the original cloud heater + in a similar way that the API would. + """ + + def calculate_heating(): + if ( + cloud_heater.power_status + and cloud_heater.set_temp > cloud_heater.current_temp + ): + cloud_heater.is_heating = True + + def set_temperature(device_id: str, set_temp: float): + assert device_id == HEATER_ID, "set_temperature called with wrong device_id" + + cloud_heater.set_temp = set_temp + + calculate_heating() + + def heater_control(device_id: str, power_status: bool): + assert device_id == HEATER_ID, "set_temperature called with wrong device_id" + + # power_status gives the "do we want to heat, Y/N", while is_heating is based on temperature and internal state and whatnot. + cloud_heater.power_status = power_status + + calculate_heating() + + cloud_heater_set_temp.side_effect = set_temperature + cloud_heater_control.side_effect = heater_control + + return cloud_heater + + +## LOCAL HEATER INTEGRATION + + +@pytest.fixture +async def local_heater(hass: HomeAssistant, mock_mill_local: MagicMock) -> dict: + """Local Mill Heater. + + This returns a by-reference status dict + with which this heater's information is organised and updated. + """ + config_entry = MockConfigEntry( + domain=DOMAIN, + data={ + mill.CONF_IP_ADDRESS: "192.168.1.59", + mill.CONNECTION_TYPE: mill.LOCAL, + }, + ) + config_entry.add_to_hass(hass) + + # We just need to load the climate component. + with patch("homeassistant.components.mill.PLATFORMS", [Platform.CLIMATE]): + assert await hass.config_entries.async_setup(config_entry.entry_id) + + await hass.async_block_till_done() + + return mock_mill_local._status + + +@pytest.fixture +async def local_heater_set_target_temperature( + mock_mill_local: MagicMock, local_heater: MagicMock +): + """Gets mock for the local heater `set_target_temperature` method.""" + return mock_mill_local.set_target_temperature + + +@pytest.fixture +async def local_heater_set_mode_control_individually( + mock_mill_local: MagicMock, local_heater: MagicMock +): + """Gets mock for the local heater `set_operation_mode_control_individually` method.""" + return mock_mill_local.set_operation_mode_control_individually + + +@pytest.fixture +async def local_heater_set_mode_off( + mock_mill_local: MagicMock, local_heater: MagicMock +): + """Gets mock for the local heater `set_operation_mode_off` method.""" + return mock_mill_local.set_operation_mode_off + + +@pytest.fixture +async def functional_local_heater( + mock_mill_local: MagicMock, + local_heater_set_target_temperature: MagicMock, + local_heater_set_mode_control_individually: MagicMock, + local_heater_set_mode_off: MagicMock, + local_heater: MagicMock, +) -> None: + """Make sure the local heater is "functional". + + This will create a pseudo-functional local heater, + meaning that function calls will edit the original local heater + in a similar way that the API would. + """ + + def set_temperature(target_temperature: float): + local_heater["set_temperature"] = target_temperature + + def set_operation_mode(operation_mode: OperationMode): + local_heater["operation_mode"] = operation_mode.value + + def mode_control_individually(): + set_operation_mode(OperationMode.CONTROL_INDIVIDUALLY) + + def mode_off(): + set_operation_mode(OperationMode.OFF) + + local_heater_set_target_temperature.side_effect = set_temperature + local_heater_set_mode_control_individually.side_effect = mode_control_individually + local_heater_set_mode_off.side_effect = mode_off + + +### CLOUD + + +@pytest.mark.parametrize( + ( + "before_state", + "before_attrs", + "service_name", + "service_params", + "effect", + "heater_control_calls", + "heater_set_temp_calls", + "after_state", + "after_attrs", + ), + [ + # set_hvac_mode + ( + HVACMode.OFF, + {}, + SERVICE_SET_HVAC_MODE, + {ATTR_HVAC_MODE: HVACMode.HEAT}, + NULL_EFFECT, + [call(HEATER_ID, power_status=True)], + [], + HVACMode.HEAT, + {}, + ), + ( + HVACMode.OFF, + {}, + SERVICE_SET_HVAC_MODE, + {ATTR_HVAC_MODE: HVACMode.OFF}, + NULL_EFFECT, + [call(HEATER_ID, power_status=False)], + [], + HVACMode.OFF, + {}, + ), + ( + HVACMode.OFF, + {}, + SERVICE_SET_HVAC_MODE, + {ATTR_HVAC_MODE: HVACMode.COOL}, + pytest.raises(HomeAssistantError), + [], + [], + HVACMode.OFF, + {}, + ), + # set_temperature (with hvac mode) + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE, ATTR_HVAC_MODE: HVACMode.HEAT}, + NULL_EFFECT, + [call(HEATER_ID, power_status=True)], + [call(HEATER_ID, float(TEST_SET_TEMPERATURE))], + HVACMode.HEAT, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + ), + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE, ATTR_HVAC_MODE: HVACMode.OFF}, + NULL_EFFECT, + [call(HEATER_ID, power_status=False)], + [call(HEATER_ID, float(TEST_SET_TEMPERATURE))], + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + ), + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + NULL_EFFECT, + [], + [call(HEATER_ID, float(TEST_SET_TEMPERATURE))], + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + ), + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE, ATTR_HVAC_MODE: HVACMode.COOL}, + pytest.raises(HomeAssistantError), + # MillHeater will set the temperature before calling async_handle_set_hvac_mode, + # meaning an invalid HVAC mode will raise only after the temperature is set. + [], + [call(HEATER_ID, float(TEST_SET_TEMPERATURE))], + HVACMode.OFF, + # likewise, in this test, it hasn't had the chance to update its ambient temperature, + # because the exception is raised before a refresh can be requested from the coordinator + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + ), + ], +) +async def test_cloud_heater( + recorder_mock: Recorder, + hass: HomeAssistant, + functional_cloud_heater: MagicMock, + cloud_heater_control: MagicMock, + cloud_heater_set_temp: MagicMock, + before_state: HVACMode, + before_attrs: dict, + service_name: str, + service_params: dict, + effect: "contextlib.AbstractContextManager", + heater_control_calls: list, + heater_set_temp_calls: list, + after_state: HVACMode, + after_attrs: dict, +) -> None: + """Tests setting HVAC mode (directly or through set_temperature) for a cloud heater.""" + + state = hass.states.get(ENTITY_CLIMATE) + assert state is not None + assert state.state == before_state + for attr, value in before_attrs.items(): + assert state.attributes.get(attr) == value + + with effect: + await hass.services.async_call( + CLIMATE_DOMAIN, + service_name, + service_params | {ATTR_ENTITY_ID: ENTITY_CLIMATE}, + blocking=True, + ) + + await hass.async_block_till_done() + + cloud_heater_control.assert_has_calls(heater_control_calls) + cloud_heater_set_temp.assert_has_calls(heater_set_temp_calls) + + state = hass.states.get(ENTITY_CLIMATE) + assert state is not None + assert state.state == after_state + for attr, value in after_attrs.items(): + assert state.attributes.get(attr) == value + + +### LOCAL + + +@pytest.mark.parametrize( + ( + "before_state", + "before_attrs", + "service_name", + "service_params", + "effect", + "heater_mode_set_individually_calls", + "heater_mode_set_off_calls", + "heater_set_target_temperature_calls", + "after_state", + "after_attrs", + ), + [ + # set_hvac_mode + ( + HVACMode.OFF, + {}, + SERVICE_SET_HVAC_MODE, + {ATTR_HVAC_MODE: HVACMode.HEAT}, + NULL_EFFECT, + [call()], + [], + [], + HVACMode.HEAT, + {}, + ), + ( + HVACMode.OFF, + {}, + SERVICE_SET_HVAC_MODE, + {ATTR_HVAC_MODE: HVACMode.OFF}, + NULL_EFFECT, + [], + [call()], + [], + HVACMode.OFF, + {}, + ), + ( + HVACMode.OFF, + {}, + SERVICE_SET_HVAC_MODE, + {ATTR_HVAC_MODE: HVACMode.COOL}, + pytest.raises(HomeAssistantError), + [], + [], + [], + HVACMode.OFF, + {}, + ), + # set_temperature (with hvac mode) + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE, ATTR_HVAC_MODE: HVACMode.HEAT}, + NULL_EFFECT, + [call()], + [], + [call(float(TEST_SET_TEMPERATURE))], + HVACMode.HEAT, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + ), + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE, ATTR_HVAC_MODE: HVACMode.OFF}, + NULL_EFFECT, + [], + [call()], + [call(float(TEST_SET_TEMPERATURE))], + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + ), + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + NULL_EFFECT, + [], + [], + [call(float(TEST_SET_TEMPERATURE))], + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE}, + ), + ( + HVACMode.OFF, + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + SERVICE_SET_TEMPERATURE, + {ATTR_TEMPERATURE: TEST_SET_TEMPERATURE, ATTR_HVAC_MODE: HVACMode.COOL}, + pytest.raises(HomeAssistantError), + # LocalMillHeater will set the temperature before calling async_handle_set_hvac_mode, + # meaning an invalid HVAC mode will raise only after the temperature is set. + [], + [], + [call(float(TEST_SET_TEMPERATURE))], + HVACMode.OFF, + # likewise, in this test, it hasn't had the chance to update its ambient temperature, + # because the exception is raised before a refresh can be requested from the coordinator + {ATTR_TEMPERATURE: TEST_AMBIENT_TEMPERATURE}, + ), + ], +) +async def test_local_heater( + hass: HomeAssistant, + functional_local_heater: MagicMock, + local_heater_set_mode_control_individually: MagicMock, + local_heater_set_mode_off: MagicMock, + local_heater_set_target_temperature: MagicMock, + before_state: HVACMode, + before_attrs: dict, + service_name: str, + service_params: dict, + effect: "contextlib.AbstractContextManager", + heater_mode_set_individually_calls: list, + heater_mode_set_off_calls: list, + heater_set_target_temperature_calls: list, + after_state: HVACMode, + after_attrs: dict, +) -> None: + """Tests setting HVAC mode (directly or through set_temperature) for a local heater.""" + + state = hass.states.get(ENTITY_CLIMATE) + assert state is not None + assert state.state == before_state + for attr, value in before_attrs.items(): + assert state.attributes.get(attr) == value + + with effect: + await hass.services.async_call( + CLIMATE_DOMAIN, + service_name, + service_params | {ATTR_ENTITY_ID: ENTITY_CLIMATE}, + blocking=True, + ) + await hass.async_block_till_done() + + local_heater_set_mode_control_individually.assert_has_calls( + heater_mode_set_individually_calls + ) + local_heater_set_mode_off.assert_has_calls(heater_mode_set_off_calls) + local_heater_set_target_temperature.assert_has_calls( + heater_set_target_temperature_calls + ) + + state = hass.states.get(ENTITY_CLIMATE) + assert state is not None + assert state.state == after_state + for attr, value in after_attrs.items(): + assert state.attributes.get(attr) == value diff --git a/tests/components/minecraft_server/conftest.py b/tests/components/minecraft_server/conftest.py index 67b8bd17b3a..e8d7a185141 100644 --- a/tests/components/minecraft_server/conftest.py +++ b/tests/components/minecraft_server/conftest.py @@ -41,3 +41,19 @@ def bedrock_mock_config_entry() -> MockConfigEntry: }, version=3, ) + + +@pytest.fixture +def legacy_java_mock_config_entry() -> MockConfigEntry: + """Create legacy Java Edition mock config entry.""" + return MockConfigEntry( + domain=DOMAIN, + unique_id=None, + entry_id=TEST_CONFIG_ENTRY_ID, + title=TEST_ADDRESS, + data={ + CONF_ADDRESS: TEST_ADDRESS, + CONF_TYPE: MinecraftServerType.LEGACY_JAVA_EDITION, + }, + version=3, + ) diff --git a/tests/components/minecraft_server/const.py b/tests/components/minecraft_server/const.py index 2c577e45d21..0fb8e994133 100644 --- a/tests/components/minecraft_server/const.py +++ b/tests/components/minecraft_server/const.py @@ -8,6 +8,9 @@ from mcstatus.responses import ( JavaStatusPlayers, JavaStatusResponse, JavaStatusVersion, + LegacyStatusPlayers, + LegacyStatusResponse, + LegacyStatusVersion, RawJavaResponse, RawJavaResponsePlayer, RawJavaResponsePlayers, @@ -81,3 +84,10 @@ TEST_BEDROCK_DATA = MinecraftServerData( game_mode="Dummy Game Mode", map_name="Dummy Map Name", ) + +TEST_LEGACY_JAVA_STATUS_RESPONSE = LegacyStatusResponse( + players=LegacyStatusPlayers(online=3, max=10), + version=LegacyStatusVersion(name="1.6.4", protocol=78), + motd=Motd.parse("Dummy MOTD"), + latency=5, +) diff --git a/tests/components/minecraft_server/snapshots/test_binary_sensor.ambr b/tests/components/minecraft_server/snapshots/test_binary_sensor.ambr index c93a87d70d8..df95e712430 100644 --- a/tests/components/minecraft_server/snapshots/test_binary_sensor.ambr +++ b/tests/components/minecraft_server/snapshots/test_binary_sensor.ambr @@ -27,6 +27,20 @@ 'state': 'on', }) # --- +# name: test_binary_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'connectivity', + 'friendly_name': 'mc.dummyserver.com:25566 Status', + }), + 'context': , + 'entity_id': 'binary_sensor.mc_dummyserver_com_25566_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_binary_sensor_update[bedrock_mock_config_entry-BedrockServer-lookup-status_response1] StateSnapshot({ 'attributes': ReadOnlyDict({ @@ -55,3 +69,17 @@ 'state': 'on', }) # --- +# name: test_binary_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'connectivity', + 'friendly_name': 'mc.dummyserver.com:25566 Status', + }), + 'context': , + 'entity_id': 'binary_sensor.mc_dummyserver_com_25566_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- diff --git a/tests/components/minecraft_server/snapshots/test_diagnostics.ambr b/tests/components/minecraft_server/snapshots/test_diagnostics.ambr index b722f4122f3..ed744977699 100644 --- a/tests/components/minecraft_server/snapshots/test_diagnostics.ambr +++ b/tests/components/minecraft_server/snapshots/test_diagnostics.ambr @@ -53,3 +53,30 @@ }), }) # --- +# name: test_config_entry_diagnostics[legacy_java_mock_config_entry-LegacyServer-status_response2] + dict({ + 'config_entry': dict({ + 'entry_id': '01234567890123456789012345678901', + 'unique_id': None, + 'version': 3, + }), + 'config_entry_data': dict({ + 'address': '**REDACTED**', + 'type': 'Legacy Java Edition', + }), + 'config_entry_options': dict({ + }), + 'server_data': dict({ + 'edition': None, + 'game_mode': None, + 'latency': 5, + 'map_name': None, + 'motd': 'Dummy MOTD', + 'players_list': None, + 'players_max': 10, + 'players_online': 3, + 'protocol_version': 78, + 'version': '1.6.4', + }), + }) +# --- diff --git a/tests/components/minecraft_server/snapshots/test_sensor.ambr b/tests/components/minecraft_server/snapshots/test_sensor.ambr index d2b044c06f5..5a6e8ad515a 100644 --- a/tests/components/minecraft_server/snapshots/test_sensor.ambr +++ b/tests/components/minecraft_server/snapshots/test_sensor.ambr @@ -205,6 +205,87 @@ 'state': '123', }) # --- +# name: test_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Latency', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_latency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5', + }) +# --- +# name: test_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].1 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Players online', + 'unit_of_measurement': 'players', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_players_online', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3', + }) +# --- +# name: test_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].2 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Players max', + 'unit_of_measurement': 'players', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_players_max', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10', + }) +# --- +# name: test_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].3 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 World message', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_world_message', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Dummy MOTD', + }) +# --- +# name: test_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].4 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Version', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_version', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.6.4', + }) +# --- +# name: test_sensor[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].5 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Protocol version', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_protocol_version', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '78', + }) +# --- # name: test_sensor_update[bedrock_mock_config_entry-BedrockServer-lookup-status_response1-entity_ids1] StateSnapshot({ 'attributes': ReadOnlyDict({ @@ -411,3 +492,84 @@ 'state': '123', }) # --- +# name: test_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Latency', + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_latency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5', + }) +# --- +# name: test_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].1 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Players online', + 'unit_of_measurement': 'players', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_players_online', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3', + }) +# --- +# name: test_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].2 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Players max', + 'unit_of_measurement': 'players', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_players_max', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10', + }) +# --- +# name: test_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].3 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 World message', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_world_message', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Dummy MOTD', + }) +# --- +# name: test_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].4 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Version', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_version', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.6.4', + }) +# --- +# name: test_sensor_update[legacy_java_mock_config_entry-LegacyServer-async_lookup-status_response2-entity_ids2].5 + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'mc.dummyserver.com:25566 Protocol version', + }), + 'context': , + 'entity_id': 'sensor.mc_dummyserver_com_25566_protocol_version', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '78', + }) +# --- diff --git a/tests/components/minecraft_server/test_binary_sensor.py b/tests/components/minecraft_server/test_binary_sensor.py index a3b71b2442f..4e154bc41f9 100644 --- a/tests/components/minecraft_server/test_binary_sensor.py +++ b/tests/components/minecraft_server/test_binary_sensor.py @@ -4,7 +4,7 @@ from datetime import timedelta from unittest.mock import patch from freezegun.api import FrozenDateTimeFactory -from mcstatus import BedrockServer, JavaServer +from mcstatus import BedrockServer, JavaServer, LegacyServer from mcstatus.responses import BedrockStatusResponse, JavaStatusResponse import pytest from syrupy.assertion import SnapshotAssertion @@ -16,6 +16,7 @@ from .const import ( TEST_BEDROCK_STATUS_RESPONSE, TEST_HOST, TEST_JAVA_STATUS_RESPONSE, + TEST_LEGACY_JAVA_STATUS_RESPONSE, TEST_PORT, ) @@ -37,6 +38,12 @@ from tests.common import async_fire_time_changed "lookup", TEST_BEDROCK_STATUS_RESPONSE, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), ], ) async def test_binary_sensor( @@ -84,6 +91,12 @@ async def test_binary_sensor( "lookup", TEST_BEDROCK_STATUS_RESPONSE, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), ], ) async def test_binary_sensor_update( @@ -135,6 +148,12 @@ async def test_binary_sensor_update( "lookup", TEST_BEDROCK_STATUS_RESPONSE, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), ], ) async def test_binary_sensor_update_failure( diff --git a/tests/components/minecraft_server/test_config_flow.py b/tests/components/minecraft_server/test_config_flow.py index c57b74c6a65..26ea7aa5067 100644 --- a/tests/components/minecraft_server/test_config_flow.py +++ b/tests/components/minecraft_server/test_config_flow.py @@ -2,7 +2,7 @@ from unittest.mock import patch -from mcstatus import BedrockServer, JavaServer +from mcstatus import BedrockServer, JavaServer, LegacyServer from homeassistant.components.minecraft_server.api import MinecraftServerType from homeassistant.components.minecraft_server.const import DOMAIN @@ -16,6 +16,7 @@ from .const import ( TEST_BEDROCK_STATUS_RESPONSE, TEST_HOST, TEST_JAVA_STATUS_RESPONSE, + TEST_LEGACY_JAVA_STATUS_RESPONSE, TEST_PORT, ) @@ -88,6 +89,43 @@ async def test_full_flow_bedrock(hass: HomeAssistant) -> None: assert result["data"][CONF_TYPE] == MinecraftServerType.BEDROCK_EDITION +async def test_full_flow_legacy_java(hass: HomeAssistant) -> None: + """Test config entry in case of a successful connection to a legacy Java Edition server.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + with ( + patch( + "homeassistant.components.minecraft_server.api.BedrockServer.lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.JavaServer.async_lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_lookup", + return_value=LegacyServer(host=TEST_HOST, port=TEST_PORT), + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_status", + return_value=TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == USER_INPUT[CONF_ADDRESS] + assert result["data"][CONF_ADDRESS] == TEST_ADDRESS + assert result["data"][CONF_TYPE] == MinecraftServerType.LEGACY_JAVA_EDITION + + async def test_service_already_configured_java( hass: HomeAssistant, java_mock_config_entry: MockConfigEntry ) -> None: @@ -138,6 +176,37 @@ async def test_service_already_configured_bedrock( assert result["reason"] == "already_configured" +async def test_service_already_configured_legacy_java( + hass: HomeAssistant, legacy_java_mock_config_entry: MockConfigEntry +) -> None: + """Test config flow abort if a legacy Java Edition server is already configured.""" + legacy_java_mock_config_entry.add_to_hass(hass) + + with ( + patch( + "homeassistant.components.minecraft_server.api.BedrockServer.lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.JavaServer.async_lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_lookup", + return_value=LegacyServer(host=TEST_HOST, port=TEST_PORT), + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_status", + return_value=TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT + ) + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + async def test_recovery_java(hass: HomeAssistant) -> None: """Test config flow recovery with a Java Edition server (successful connection after a failed connection).""" with ( @@ -218,3 +287,56 @@ async def test_recovery_bedrock(hass: HomeAssistant) -> None: assert result2["title"] == USER_INPUT[CONF_ADDRESS] assert result2["data"][CONF_ADDRESS] == TEST_ADDRESS assert result2["data"][CONF_TYPE] == MinecraftServerType.BEDROCK_EDITION + + +async def test_recovery_legacy_java(hass: HomeAssistant) -> None: + """Test config flow recovery with a legacy Java Edition server (successful connection after a failed connection).""" + with ( + patch( + "homeassistant.components.minecraft_server.api.BedrockServer.lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.JavaServer.async_lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_lookup", + return_value=LegacyServer(host=TEST_HOST, port=TEST_PORT), + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_status", + side_effect=OSError, + ), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=USER_INPUT + ) + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": "cannot_connect"} + + with ( + patch( + "homeassistant.components.minecraft_server.api.BedrockServer.lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.JavaServer.async_lookup", + side_effect=ValueError, + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_lookup", + return_value=LegacyServer(host=TEST_HOST, port=TEST_PORT), + ), + patch( + "homeassistant.components.minecraft_server.api.LegacyServer.async_status", + return_value=TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), + ): + result2 = await hass.config_entries.flow.async_configure( + flow_id=result["flow_id"], user_input=USER_INPUT + ) + assert result2["type"] is FlowResultType.CREATE_ENTRY + assert result2["title"] == USER_INPUT[CONF_ADDRESS] + assert result2["data"][CONF_ADDRESS] == TEST_ADDRESS + assert result2["data"][CONF_TYPE] == MinecraftServerType.LEGACY_JAVA_EDITION diff --git a/tests/components/minecraft_server/test_diagnostics.py b/tests/components/minecraft_server/test_diagnostics.py index d576b31ca5d..1fd388af95d 100644 --- a/tests/components/minecraft_server/test_diagnostics.py +++ b/tests/components/minecraft_server/test_diagnostics.py @@ -2,8 +2,12 @@ from unittest.mock import patch -from mcstatus import BedrockServer, JavaServer -from mcstatus.responses import BedrockStatusResponse, JavaStatusResponse +from mcstatus import BedrockServer, JavaServer, LegacyServer +from mcstatus.responses import ( + BedrockStatusResponse, + JavaStatusResponse, + LegacyStatusResponse, +) import pytest from syrupy.assertion import SnapshotAssertion @@ -13,6 +17,7 @@ from .const import ( TEST_BEDROCK_STATUS_RESPONSE, TEST_HOST, TEST_JAVA_STATUS_RESPONSE, + TEST_LEGACY_JAVA_STATUS_RESPONSE, TEST_PORT, ) @@ -26,14 +31,19 @@ from tests.typing import ClientSessionGenerator [ ("java_mock_config_entry", JavaServer, TEST_JAVA_STATUS_RESPONSE), ("bedrock_mock_config_entry", BedrockServer, TEST_BEDROCK_STATUS_RESPONSE), + ( + "legacy_java_mock_config_entry", + LegacyServer, + TEST_LEGACY_JAVA_STATUS_RESPONSE, + ), ], ) async def test_config_entry_diagnostics( hass: HomeAssistant, hass_client: ClientSessionGenerator, mock_config_entry: MockConfigEntry, - server: JavaServer | BedrockServer, - status_response: JavaStatusResponse | BedrockStatusResponse, + server: JavaServer | BedrockServer | LegacyServer, + status_response: JavaStatusResponse | BedrockStatusResponse | LegacyStatusResponse, request: pytest.FixtureRequest, snapshot: SnapshotAssertion, ) -> None: @@ -43,10 +53,10 @@ async def test_config_entry_diagnostics( mock_config_entry = request.getfixturevalue(mock_config_entry) mock_config_entry.add_to_hass(hass) - if server.__name__ == "JavaServer": - lookup_function_name = "async_lookup" - else: + if server.__name__ == "BedrockServer": lookup_function_name = "lookup" + else: + lookup_function_name = "async_lookup" # Setup mock entry. with ( diff --git a/tests/components/minecraft_server/test_sensor.py b/tests/components/minecraft_server/test_sensor.py index daa20d16a66..98116e22ed4 100644 --- a/tests/components/minecraft_server/test_sensor.py +++ b/tests/components/minecraft_server/test_sensor.py @@ -4,8 +4,12 @@ from datetime import timedelta from unittest.mock import patch from freezegun.api import FrozenDateTimeFactory -from mcstatus import BedrockServer, JavaServer -from mcstatus.responses import BedrockStatusResponse, JavaStatusResponse +from mcstatus import BedrockServer, JavaServer, LegacyServer +from mcstatus.responses import ( + BedrockStatusResponse, + JavaStatusResponse, + LegacyStatusResponse, +) import pytest from syrupy.assertion import SnapshotAssertion @@ -16,6 +20,7 @@ from .const import ( TEST_BEDROCK_STATUS_RESPONSE, TEST_HOST, TEST_JAVA_STATUS_RESPONSE, + TEST_LEGACY_JAVA_STATUS_RESPONSE, TEST_PORT, ) @@ -78,14 +83,21 @@ BEDROCK_SENSOR_ENTITIES_DISABLED_BY_DEFAULT: list[str] = [ TEST_BEDROCK_STATUS_RESPONSE, BEDROCK_SENSOR_ENTITIES, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + JAVA_SENSOR_ENTITIES, + ), ], ) async def test_sensor( hass: HomeAssistant, mock_config_entry: str, - server: JavaServer | BedrockServer, + server: JavaServer | BedrockServer | LegacyServer, lookup_function_name: str, - status_response: JavaStatusResponse | BedrockStatusResponse, + status_response: JavaStatusResponse | BedrockStatusResponse | LegacyStatusResponse, entity_ids: list[str], request: pytest.FixtureRequest, snapshot: SnapshotAssertion, @@ -133,14 +145,21 @@ async def test_sensor( TEST_BEDROCK_STATUS_RESPONSE, BEDROCK_SENSOR_ENTITIES_DISABLED_BY_DEFAULT, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + JAVA_SENSOR_ENTITIES_DISABLED_BY_DEFAULT, + ), ], ) async def test_sensor_disabled_by_default( hass: HomeAssistant, mock_config_entry: str, - server: JavaServer | BedrockServer, + server: JavaServer | BedrockServer | LegacyServer, lookup_function_name: str, - status_response: JavaStatusResponse | BedrockStatusResponse, + status_response: JavaStatusResponse | BedrockStatusResponse | LegacyStatusResponse, entity_ids: list[str], request: pytest.FixtureRequest, ) -> None: @@ -188,14 +207,21 @@ async def test_sensor_disabled_by_default( TEST_BEDROCK_STATUS_RESPONSE, BEDROCK_SENSOR_ENTITIES, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + JAVA_SENSOR_ENTITIES, + ), ], ) async def test_sensor_update( hass: HomeAssistant, mock_config_entry: str, - server: JavaServer | BedrockServer, + server: JavaServer | BedrockServer | LegacyServer, lookup_function_name: str, - status_response: JavaStatusResponse | BedrockStatusResponse, + status_response: JavaStatusResponse | BedrockStatusResponse | LegacyStatusResponse, entity_ids: list[str], request: pytest.FixtureRequest, snapshot: SnapshotAssertion, @@ -248,14 +274,21 @@ async def test_sensor_update( TEST_BEDROCK_STATUS_RESPONSE, BEDROCK_SENSOR_ENTITIES, ), + ( + "legacy_java_mock_config_entry", + LegacyServer, + "async_lookup", + TEST_LEGACY_JAVA_STATUS_RESPONSE, + JAVA_SENSOR_ENTITIES, + ), ], ) async def test_sensor_update_failure( hass: HomeAssistant, mock_config_entry: str, - server: JavaServer | BedrockServer, + server: JavaServer | BedrockServer | LegacyServer, lookup_function_name: str, - status_response: JavaStatusResponse | BedrockStatusResponse, + status_response: JavaStatusResponse | BedrockStatusResponse | LegacyStatusResponse, entity_ids: list[str], request: pytest.FixtureRequest, freezer: FrozenDateTimeFactory, diff --git a/tests/components/mobile_app/test_notify.py b/tests/components/mobile_app/test_notify.py index 57f7933b00f..d2cb4a230df 100644 --- a/tests/components/mobile_app/test_notify.py +++ b/tests/components/mobile_app/test_notify.py @@ -149,7 +149,15 @@ async def test_notify_works( """Test notify works.""" assert hass.services.has_service("notify", "mobile_app_test") is True await hass.services.async_call( - "notify", "mobile_app_test", {"message": "Hello world"}, blocking=True + "notify", + "mobile_app_test", + { + "message": "Hello world", + "title": "Demo", + "target": ["mock-webhook_id"], + "data": {"field1": "value1"}, + }, + blocking=True, ) assert len(aioclient_mock.mock_calls) == 1 @@ -159,6 +167,8 @@ async def test_notify_works( assert call_json["push_token"] == "PUSH_TOKEN" assert call_json["message"] == "Hello world" + assert call_json["title"] == "Demo" + assert call_json["data"] == {"field1": "value1"} assert call_json["registration_info"]["app_id"] == "io.homeassistant.mobile_app" assert call_json["registration_info"]["app_version"] == "1.0" assert call_json["registration_info"]["webhook_id"] == "mock-webhook_id" diff --git a/tests/components/moehlenhoff_alpha2/snapshots/test_binary_sensor.ambr b/tests/components/moehlenhoff_alpha2/snapshots/test_binary_sensor.ambr index 5ea055b5347..904b3fc4e14 100644 --- a/tests/components/moehlenhoff_alpha2/snapshots/test_binary_sensor.ambr +++ b/tests/components/moehlenhoff_alpha2/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Büro IO device 1 battery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/moehlenhoff_alpha2/snapshots/test_button.ambr b/tests/components/moehlenhoff_alpha2/snapshots/test_button.ambr index 9104b7473b4..36a2fbded08 100644 --- a/tests/components/moehlenhoff_alpha2/snapshots/test_button.ambr +++ b/tests/components/moehlenhoff_alpha2/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync time', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/moehlenhoff_alpha2/snapshots/test_climate.ambr b/tests/components/moehlenhoff_alpha2/snapshots/test_climate.ambr index 57f1b2fdc25..a248cd896e8 100644 --- a/tests/components/moehlenhoff_alpha2/snapshots/test_climate.ambr +++ b/tests/components/moehlenhoff_alpha2/snapshots/test_climate.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Büro', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/moehlenhoff_alpha2/snapshots/test_sensor.ambr b/tests/components/moehlenhoff_alpha2/snapshots/test_sensor.ambr index 28df23dd089..82c63f3cc1f 100644 --- a/tests/components/moehlenhoff_alpha2/snapshots/test_sensor.ambr +++ b/tests/components/moehlenhoff_alpha2/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Büro heat control 1 valve opening', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/monarch_money/snapshots/test_sensor.ambr b/tests/components/monarch_money/snapshots/test_sensor.ambr index 65f85925114..57702d7e1b2 100644 --- a/tests/components/monarch_money/snapshots/test_sensor.ambr +++ b/tests/components/monarch_money/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Expense year to date', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Income year to date', 'options': dict({ }), 'original_device_class': , @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Savings rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Savings year to date', 'options': dict({ }), 'original_device_class': , @@ -233,6 +237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -285,6 +290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -337,6 +343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -390,6 +397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -442,6 +450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -495,6 +504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -547,6 +557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -600,6 +611,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -652,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -705,6 +718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -757,6 +771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -810,6 +825,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -862,6 +878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -915,6 +932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -965,6 +983,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -1017,6 +1036,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Value', 'options': dict({ }), 'original_device_class': , @@ -1072,6 +1092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -1125,6 +1146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/monzo/snapshots/test_sensor.ambr b/tests/components/monzo/snapshots/test_sensor.ambr index bd6fd4c5daf..53438d6f29d 100644 --- a/tests/components/monzo/snapshots/test_sensor.ambr +++ b/tests/components/monzo/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total balance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total balance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -236,6 +240,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/mqtt/test_device_trigger.py b/tests/components/mqtt/test_device_trigger.py index ecf922e54a1..511b5720406 100644 --- a/tests/components/mqtt/test_device_trigger.py +++ b/tests/components/mqtt/test_device_trigger.py @@ -22,11 +22,6 @@ from tests.common import async_fire_mqtt_message, async_get_device_automations from tests.typing import MqttMockHAClientGenerator, WebSocketGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( ("discovery_topic", "data"), [ diff --git a/tests/components/mqtt/test_trigger.py b/tests/components/mqtt/test_trigger.py index 5bf36849b13..88542f8afbf 100644 --- a/tests/components/mqtt/test_trigger.py +++ b/tests/components/mqtt/test_trigger.py @@ -13,11 +13,6 @@ from tests.common import async_fire_mqtt_message, mock_component from tests.typing import MqttMockHAClient, MqttMockHAClientGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) async def setup_comp( hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator diff --git a/tests/components/music_assistant/snapshots/test_button.ambr b/tests/components/music_assistant/snapshots/test_button.ambr index d064916e044..70991e3669c 100644 --- a/tests/components/music_assistant/snapshots/test_button.ambr +++ b/tests/components/music_assistant/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Favorite current song', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Favorite current song', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Favorite current song', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/music_assistant/snapshots/test_media_player.ambr b/tests/components/music_assistant/snapshots/test_media_player.ambr index 8547fd1c161..5b2bcbd48c4 100644 --- a/tests/components/music_assistant/snapshots/test_media_player.ambr +++ b/tests/components/music_assistant/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -89,6 +90,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -165,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/myuplink/snapshots/test_binary_sensor.ambr b/tests/components/myuplink/snapshots/test_binary_sensor.ambr index 52b3f2314f8..a37a3bf9d37 100644 --- a/tests/components/myuplink/snapshots/test_binary_sensor.ambr +++ b/tests/components/myuplink/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extern. adjust\xadment climate system 1', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extern. adjust\xadment climate system 1', 'options': dict({ }), 'original_device_class': None, @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump: Heating medium (GP1)', 'options': dict({ }), 'original_device_class': None, @@ -311,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump: Heating medium (GP1)', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/myuplink/snapshots/test_number.ambr b/tests/components/myuplink/snapshots/test_number.ambr index f8a290f89e3..81cd7939e30 100644 --- a/tests/components/myuplink/snapshots/test_number.ambr +++ b/tests/components/myuplink/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Degree minutes', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Degree minutes', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating offset climate system 1', 'options': dict({ }), 'original_device_class': None, @@ -198,6 +201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating offset climate system 1', 'options': dict({ }), 'original_device_class': None, @@ -255,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room sensor set point value heating climate system 1', 'options': dict({ }), 'original_device_class': None, @@ -312,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room sensor set point value heating climate system 1', 'options': dict({ }), 'original_device_class': None, @@ -369,6 +375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'start diff additional heat', 'options': dict({ }), 'original_device_class': None, @@ -427,6 +434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'start diff additional heat', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/myuplink/snapshots/test_select.ambr b/tests/components/myuplink/snapshots/test_select.ambr index 08c4244d0f6..b8a40c1356c 100644 --- a/tests/components/myuplink/snapshots/test_select.ambr +++ b/tests/components/myuplink/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'comfort mode', 'options': dict({ }), 'original_device_class': None, @@ -88,6 +89,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'comfort mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/myuplink/snapshots/test_sensor.ambr b/tests/components/myuplink/snapshots/test_sensor.ambr index 06b2612da1b..aaecd5b9184 100644 --- a/tests/components/myuplink/snapshots/test_sensor.ambr +++ b/tests/components/myuplink/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average outdoor temp (BT1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average outdoor temp (BT1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calculated supply climate system 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calculated supply climate system 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condenser (BT12)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condenser (BT12)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (BE1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (BE1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (BE2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (BE2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (BE3)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -638,6 +649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current (BE3)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -694,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current compressor frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -750,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current compressor frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -804,6 +818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current fan mode', 'options': dict({ }), 'original_device_class': None, @@ -852,6 +867,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current fan mode', 'options': dict({ }), 'original_device_class': None, @@ -900,6 +916,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current hot water mode', 'options': dict({ }), 'original_device_class': None, @@ -949,6 +966,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current hot water mode', 'options': dict({ }), 'original_device_class': None, @@ -1000,6 +1018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current outd temp (BT1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1056,6 +1075,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current outd temp (BT1)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1110,6 +1130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Decrease from reference value', 'options': dict({ }), 'original_device_class': None, @@ -1159,6 +1180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Decrease from reference value', 'options': dict({ }), 'original_device_class': None, @@ -1210,6 +1232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrosting time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1266,6 +1289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrosting time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1320,6 +1344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Degree minutes', 'options': dict({ }), 'original_device_class': None, @@ -1369,6 +1394,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Degree minutes', 'options': dict({ }), 'original_device_class': None, @@ -1418,6 +1444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Desired humidity', 'options': dict({ }), 'original_device_class': None, @@ -1467,6 +1494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Desired humidity', 'options': dict({ }), 'original_device_class': None, @@ -1516,6 +1544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Desired humidity', 'options': dict({ }), 'original_device_class': None, @@ -1565,6 +1594,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Desired humidity', 'options': dict({ }), 'original_device_class': None, @@ -1616,6 +1646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discharge (BT14)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1672,6 +1703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discharge (BT14)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1728,6 +1760,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'dT Inverter - exh air (BT20)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1784,6 +1817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'dT Inverter - exh air (BT20)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1840,6 +1874,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evaporator (BT16)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1896,6 +1931,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evaporator (BT16)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1952,6 +1988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exhaust air (BT20)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2008,6 +2045,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exhaust air (BT20)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2064,6 +2102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extract air (BT21)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2120,6 +2159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extract air (BT21)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2174,6 +2214,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating medium pump speed (GP1)', 'options': dict({ }), 'original_device_class': None, @@ -2223,6 +2264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating medium pump speed (GP1)', 'options': dict({ }), 'original_device_class': None, @@ -2274,6 +2316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water: charge current value ((BT12 | BT63))', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2330,6 +2373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water: charge current value ((BT12 | BT63))', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2386,6 +2430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water: charge set point value', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2442,6 +2487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water: charge set point value', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2498,6 +2544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water charging (BT6)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2554,6 +2601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water charging (BT6)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2610,6 +2658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water top (BT7)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2666,6 +2715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hot water top (BT7)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2730,6 +2780,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Int elec add heat', 'options': dict({ }), 'original_device_class': , @@ -2798,6 +2849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Int elec add heat', 'options': dict({ }), 'original_device_class': , @@ -2856,6 +2908,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Int elec add heat raw', 'options': dict({ }), 'original_device_class': None, @@ -2904,6 +2957,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Int elec add heat raw', 'options': dict({ }), 'original_device_class': None, @@ -2954,6 +3008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3010,6 +3065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3066,6 +3122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Liquid line (BT15)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3122,6 +3179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Liquid line (BT15)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3178,6 +3236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max compressor frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3234,6 +3293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max compressor frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3290,6 +3350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Min compressor frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3346,6 +3407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Min compressor frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3402,6 +3464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil temperature (BT29)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3458,6 +3521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil temperature (BT29)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3514,6 +3578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil temperature (EP15-BT29)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3570,6 +3635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil temperature (EP15-BT29)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3634,6 +3700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Priority', 'options': dict({ }), 'original_device_class': , @@ -3702,6 +3769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Priority', 'options': dict({ }), 'original_device_class': , @@ -3760,6 +3828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prior\xadity raw', 'options': dict({ }), 'original_device_class': None, @@ -3808,6 +3877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prior\xadity raw', 'options': dict({ }), 'original_device_class': None, @@ -3856,6 +3926,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'r start diff additional heat', 'options': dict({ }), 'original_device_class': None, @@ -3905,6 +3976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'r start diff additional heat', 'options': dict({ }), 'original_device_class': None, @@ -3956,6 +4028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reference, air speed sensor', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4012,6 +4085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reference, air speed sensor', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4068,6 +4142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return line (BT3)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4124,6 +4199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return line (BT3)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4180,6 +4256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return line (BT62)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4236,6 +4313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return line (BT62)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4292,6 +4370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room temperature (BT50)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4348,6 +4427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room temperature (BT50)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4409,6 +4489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status compressor', 'options': dict({ }), 'original_device_class': , @@ -4471,6 +4552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status compressor', 'options': dict({ }), 'original_device_class': , @@ -4526,6 +4608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status com\xadpressor raw', 'options': dict({ }), 'original_device_class': None, @@ -4574,6 +4657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status com\xadpressor raw', 'options': dict({ }), 'original_device_class': None, @@ -4624,6 +4708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Suction gas (BT17)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4680,6 +4765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Suction gas (BT17)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4736,6 +4822,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply line (BT2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4792,6 +4879,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply line (BT2)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4848,6 +4936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply line (BT61)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4904,6 +4993,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply line (BT61)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4958,6 +5048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time factor add heat', 'options': dict({ }), 'original_device_class': None, @@ -5007,6 +5098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time factor add heat', 'options': dict({ }), 'original_device_class': None, @@ -5056,6 +5148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Value, air velocity sensor (BS1)', 'options': dict({ }), 'original_device_class': None, @@ -5105,6 +5198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Value, air velocity sensor (BS1)', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/myuplink/snapshots/test_switch.ambr b/tests/components/myuplink/snapshots/test_switch.ambr index 4f8d690ada6..97968e61604 100644 --- a/tests/components/myuplink/snapshots/test_switch.ambr +++ b/tests/components/myuplink/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In\xadcreased venti\xadlation', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In\xadcreased venti\xadlation', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tempo\xadrary lux', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tempo\xadrary lux', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nam/snapshots/test_sensor.ambr b/tests/components/nam/snapshots/test_sensor.ambr index 7ad641306b5..f5bb45d7561 100644 --- a/tests/components/nam/snapshots/test_sensor.ambr +++ b/tests/components/nam/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BH1750 illuminance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BME280 humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BME280 pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BME280 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BMP180 pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BMP180 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BMP280 pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'BMP280 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHT22 humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHT22 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DS18B20 temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -638,6 +649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HECA humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -694,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HECA temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -748,6 +761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -799,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'MH-Z14A carbon dioxide', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -853,6 +868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PMSx003 common air quality index', 'options': dict({ }), 'original_device_class': None, @@ -909,6 +925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PMSx003 common air quality index level', 'options': dict({ }), 'original_device_class': , @@ -967,6 +984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PMSx003 PM1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1023,6 +1041,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PMSx003 PM10', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1079,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PMSx003 PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1133,6 +1153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDS011 common air quality index', 'options': dict({ }), 'original_device_class': None, @@ -1189,6 +1210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDS011 common air quality index level', 'options': dict({ }), 'original_device_class': , @@ -1247,6 +1269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDS011 PM10', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1303,6 +1326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SDS011 PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1359,6 +1383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SHT3X humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1415,6 +1440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SHT3X temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1471,6 +1497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1525,6 +1552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SPS30 common air quality index', 'options': dict({ }), 'original_device_class': None, @@ -1581,6 +1609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SPS30 common air quality index level', 'options': dict({ }), 'original_device_class': , @@ -1639,6 +1668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SPS30 PM1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1695,6 +1725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SPS30 PM10', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1751,6 +1782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SPS30 PM2.5', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1807,6 +1839,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SPS30 PM4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/namecheapdns/conftest.py b/tests/components/namecheapdns/conftest.py new file mode 100644 index 00000000000..0f17bad64b3 --- /dev/null +++ b/tests/components/namecheapdns/conftest.py @@ -0,0 +1,52 @@ +"""Common fixtures for the Namecheap DynamicDNS tests.""" + +from collections.abc import Generator +from unittest.mock import AsyncMock, patch + +import pytest + +from homeassistant.components.namecheapdns.const import DOMAIN +from homeassistant.const import CONF_DOMAIN, CONF_HOST, CONF_PASSWORD + +from tests.common import MockConfigEntry + +TEST_HOST = "home" +TEST_DOMAIN = "example.com" +TEST_PASSWORD = "test-password" + +TEST_USER_INPUT = { + CONF_HOST: TEST_HOST, + CONF_DOMAIN: TEST_DOMAIN, + CONF_PASSWORD: TEST_PASSWORD, +} + + +@pytest.fixture +def mock_setup_entry() -> Generator[AsyncMock]: + """Override async_setup_entry.""" + with patch( + "homeassistant.components.namecheapdns.async_setup_entry", return_value=True + ) as mock_setup_entry: + yield mock_setup_entry + + +@pytest.fixture(name="mock_namecheap") +def mock_update_namecheapdns() -> Generator[AsyncMock]: + """Mock update_namecheapdns.""" + + with patch( + "homeassistant.components.namecheapdns.config_flow.update_namecheapdns", + return_value=True, + ) as mock: + yield mock + + +@pytest.fixture(name="config_entry") +def mock_config_entry() -> MockConfigEntry: + """Mock Namecheap Dynamic DNS configuration entry.""" + return MockConfigEntry( + domain=DOMAIN, + title=f"{TEST_HOST}.{TEST_DOMAIN}", + data=TEST_USER_INPUT, + entry_id="12345", + ) diff --git a/tests/components/namecheapdns/test_config_flow.py b/tests/components/namecheapdns/test_config_flow.py new file mode 100644 index 00000000000..1791086c57d --- /dev/null +++ b/tests/components/namecheapdns/test_config_flow.py @@ -0,0 +1,210 @@ +"""Test the Namecheap DynamicDNS config flow.""" + +from unittest.mock import AsyncMock + +from aiohttp import ClientError +import pytest + +from homeassistant.components.namecheapdns.const import DOMAIN +from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.const import CONF_PASSWORD +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant +from homeassistant.data_entry_flow import FlowResultType +from homeassistant.helpers import issue_registry as ir +from homeassistant.setup import async_setup_component + +from .conftest import TEST_USER_INPUT + +from tests.common import MockConfigEntry + + +@pytest.mark.usefixtures("mock_namecheap") +async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None: + """Test we get the form.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {} + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + await hass.async_block_till_done() + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "home.example.com" + assert result["data"] == TEST_USER_INPUT + + assert len(mock_setup_entry.mock_calls) == 1 + + +@pytest.mark.parametrize( + ("side_effect", "text_error"), + [ + (ValueError, "unknown"), + (False, "update_failed"), + (ClientError, "cannot_connect"), + ], +) +async def test_form_errors( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_namecheap: AsyncMock, + side_effect: Exception | bool, + text_error: str, +) -> None: + """Test we handle errors.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + mock_namecheap.side_effect = [side_effect] + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": text_error} + + mock_namecheap.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + await hass.async_block_till_done() + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "home.example.com" + assert result["data"] == TEST_USER_INPUT + assert len(mock_setup_entry.mock_calls) == 1 + + +@pytest.mark.usefixtures("mock_namecheap") +async def test_import( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test import flow.""" + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data=TEST_USER_INPUT, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "home.example.com" + assert result["data"] == TEST_USER_INPUT + assert len(mock_setup_entry.mock_calls) == 1 + assert issue_registry.async_get_issue( + domain=HOMEASSISTANT_DOMAIN, + issue_id=f"deprecated_yaml_{DOMAIN}", + ) + + +async def test_import_exception( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + issue_registry: ir.IssueRegistry, + mock_namecheap: AsyncMock, +) -> None: + """Test import flow failed.""" + mock_namecheap.side_effect = [False] + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data=TEST_USER_INPUT, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "update_failed" + + assert len(mock_setup_entry.mock_calls) == 0 + + assert issue_registry.async_get_issue( + domain=DOMAIN, + issue_id="deprecated_yaml_import_issue_error", + ) + + +@pytest.mark.usefixtures("mock_namecheap") +async def test_init_import_flow( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, +) -> None: + """Test yaml triggers import flow.""" + + await async_setup_component( + hass, + DOMAIN, + {DOMAIN: TEST_USER_INPUT}, + ) + assert len(mock_setup_entry.mock_calls) == 1 + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 + + +@pytest.mark.usefixtures("mock_namecheap") +async def test_reconfigure( + hass: HomeAssistant, + config_entry: MockConfigEntry, +) -> None: + """Test reconfigure flow.""" + config_entry.add_to_hass(hass) + result = await config_entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_PASSWORD: "new-password"} + ) + await hass.async_block_till_done() + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert config_entry.data[CONF_PASSWORD] == "new-password" + + +@pytest.mark.parametrize( + ("side_effect", "text_error"), + [ + (ValueError, "unknown"), + (False, "update_failed"), + (ClientError, "cannot_connect"), + ], +) +async def test_reconfigure_errors( + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_namecheap: AsyncMock, + side_effect: Exception | bool, + text_error: str, +) -> None: + """Test we handle errors.""" + + config_entry.add_to_hass(hass) + result = await config_entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + + mock_namecheap.side_effect = [side_effect] + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_PASSWORD: "new-password"} + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": text_error} + + mock_namecheap.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_PASSWORD: "new-password"} + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + + assert config_entry.data[CONF_PASSWORD] == "new-password" diff --git a/tests/components/namecheapdns/test_init.py b/tests/components/namecheapdns/test_init.py index b7c1fe732c0..0b47e7cc03b 100644 --- a/tests/components/namecheapdns/test_init.py +++ b/tests/components/namecheapdns/test_init.py @@ -2,74 +2,79 @@ from datetime import timedelta +from aiohttp import ClientError +from freezegun.api import FrozenDateTimeFactory import pytest -from homeassistant.components import namecheapdns +from homeassistant.components.namecheapdns.const import UPDATE_URL +from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant -from homeassistant.setup import async_setup_component -from homeassistant.util.dt import utcnow -from tests.common import async_fire_time_changed +from .conftest import TEST_USER_INPUT + +from tests.common import MockConfigEntry, async_fire_time_changed from tests.test_util.aiohttp import AiohttpClientMocker -HOST = "test" -DOMAIN = "bla" -PASSWORD = "abcdefgh" - -@pytest.fixture -async def setup_namecheapdns( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +@pytest.mark.freeze_time +async def test_setup( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, ) -> None: - """Fixture that sets up NamecheapDNS.""" - aioclient_mock.get( - namecheapdns.UPDATE_URL, - params={"host": HOST, "domain": DOMAIN, "password": PASSWORD}, - text="0", - ) - - await async_setup_component( - hass, - namecheapdns.DOMAIN, - {"namecheapdns": {"host": HOST, "domain": DOMAIN, "password": PASSWORD}}, - ) - - -async def test_setup(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None: """Test setup works if update passes.""" aioclient_mock.get( - namecheapdns.UPDATE_URL, - params={"host": HOST, "domain": DOMAIN, "password": PASSWORD}, + UPDATE_URL, + params=TEST_USER_INPUT, text="0", ) - result = await async_setup_component( - hass, - namecheapdns.DOMAIN, - {"namecheapdns": {"host": HOST, "domain": DOMAIN, "password": PASSWORD}}, - ) - assert result + config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.LOADED assert aioclient_mock.call_count == 1 - async_fire_time_changed(hass, utcnow() + timedelta(minutes=5)) + freezer.tick(timedelta(minutes=5)) + async_fire_time_changed(hass) await hass.async_block_till_done() assert aioclient_mock.call_count == 2 +@pytest.mark.freeze_time async def test_setup_fails_if_update_fails( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, ) -> None: """Test setup fails if first update fails.""" aioclient_mock.get( - namecheapdns.UPDATE_URL, - params={"host": HOST, "domain": DOMAIN, "password": PASSWORD}, + UPDATE_URL, + params=TEST_USER_INPUT, text="1", ) - result = await async_setup_component( - hass, - namecheapdns.DOMAIN, - {"namecheapdns": {"host": HOST, "domain": DOMAIN, "password": PASSWORD}}, - ) - assert not result + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.SETUP_RETRY + + assert aioclient_mock.call_count == 1 + + aioclient_mock.clear_requests() + aioclient_mock.get( + UPDATE_URL, + params=TEST_USER_INPUT, + exc=ClientError, + ) + + freezer.tick(timedelta(minutes=5)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.SETUP_RETRY assert aioclient_mock.call_count == 1 diff --git a/tests/components/nanoleaf/snapshots/test_light.ambr b/tests/components/nanoleaf/snapshots/test_light.ambr index 19d857026dd..bffcb555bb2 100644 --- a/tests/components/nanoleaf/snapshots/test_light.ambr +++ b/tests/components/nanoleaf/snapshots/test_light.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nederlandse_spoorwegen/snapshots/test_binary_sensor.ambr b/tests/components/nederlandse_spoorwegen/snapshots/test_binary_sensor.ambr index e4b867960e2..f070dc2ebab 100644 --- a/tests/components/nederlandse_spoorwegen/snapshots/test_binary_sensor.ambr +++ b/tests/components/nederlandse_spoorwegen/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Arrival delayed', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure delayed', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Going', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Arrival delayed', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure delayed', 'options': dict({ }), 'original_device_class': None, @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Going', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nederlandse_spoorwegen/snapshots/test_sensor.ambr b/tests/components/nederlandse_spoorwegen/snapshots/test_sensor.ambr index b4f9bdd1ea7..9469974fc2f 100644 --- a/tests/components/nederlandse_spoorwegen/snapshots/test_sensor.ambr +++ b/tests/components/nederlandse_spoorwegen/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival time', 'options': dict({ }), 'original_device_class': , @@ -119,6 +121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure platform', 'options': dict({ }), 'original_device_class': None, @@ -168,6 +171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure time', 'options': dict({ }), 'original_device_class': , @@ -218,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure', 'options': dict({ }), 'original_device_class': , @@ -289,6 +294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next departure', 'options': dict({ }), 'original_device_class': , @@ -339,6 +345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -388,6 +395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival time', 'options': dict({ }), 'original_device_class': , @@ -438,6 +446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure platform', 'options': dict({ }), 'original_device_class': None, @@ -487,6 +496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure time', 'options': dict({ }), 'original_device_class': , @@ -537,6 +547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, @@ -591,6 +602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -645,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfers', 'options': dict({ }), 'original_device_class': None, @@ -694,6 +707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -743,6 +757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival time', 'options': dict({ }), 'original_device_class': , @@ -793,6 +808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure platform', 'options': dict({ }), 'original_device_class': None, @@ -842,6 +858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure time', 'options': dict({ }), 'original_device_class': , @@ -892,6 +909,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure', 'options': dict({ }), 'original_device_class': , @@ -963,6 +981,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next departure', 'options': dict({ }), 'original_device_class': , @@ -1013,6 +1032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -1062,6 +1082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival time', 'options': dict({ }), 'original_device_class': , @@ -1112,6 +1133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure platform', 'options': dict({ }), 'original_device_class': None, @@ -1161,6 +1183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure time', 'options': dict({ }), 'original_device_class': , @@ -1211,6 +1234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, @@ -1265,6 +1289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -1319,6 +1344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfers', 'options': dict({ }), 'original_device_class': None, @@ -1368,6 +1394,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -1417,6 +1444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival time', 'options': dict({ }), 'original_device_class': , @@ -1467,6 +1495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure platform', 'options': dict({ }), 'original_device_class': None, @@ -1516,6 +1545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure time', 'options': dict({ }), 'original_device_class': , @@ -1566,6 +1596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure', 'options': dict({ }), 'original_device_class': , @@ -1637,6 +1668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next departure', 'options': dict({ }), 'original_device_class': , @@ -1687,6 +1719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -1736,6 +1769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival time', 'options': dict({ }), 'original_device_class': , @@ -1786,6 +1820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure platform', 'options': dict({ }), 'original_device_class': None, @@ -1835,6 +1870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure time', 'options': dict({ }), 'original_device_class': , @@ -1885,6 +1921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, @@ -1939,6 +1976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -1993,6 +2031,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfers', 'options': dict({ }), 'original_device_class': None, @@ -2042,6 +2081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -2091,6 +2131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual arrival time', 'options': dict({ }), 'original_device_class': , @@ -2141,6 +2182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure platform', 'options': dict({ }), 'original_device_class': None, @@ -2190,6 +2232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actual departure time', 'options': dict({ }), 'original_device_class': , @@ -2240,6 +2283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure', 'options': dict({ }), 'original_device_class': , @@ -2311,6 +2355,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next departure', 'options': dict({ }), 'original_device_class': , @@ -2361,6 +2406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival platform', 'options': dict({ }), 'original_device_class': None, @@ -2410,6 +2456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned arrival time', 'options': dict({ }), 'original_device_class': , @@ -2460,6 +2507,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure platform', 'options': dict({ }), 'original_device_class': None, @@ -2509,6 +2557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Planned departure time', 'options': dict({ }), 'original_device_class': , @@ -2559,6 +2608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, @@ -2613,6 +2663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -2667,6 +2718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfers', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_binary_sensor.ambr b/tests/components/netatmo/snapshots/test_binary_sensor.ambr index 0cf44637a77..fe50b59f183 100644 --- a/tests/components/netatmo/snapshots/test_binary_sensor.ambr +++ b/tests/components/netatmo/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -228,6 +232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -330,6 +336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -380,6 +387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -432,6 +440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -482,6 +491,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -532,6 +542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/netatmo/snapshots/test_button.ambr b/tests/components/netatmo/snapshots/test_button.ambr index e43d58ee962..908e98ac55a 100644 --- a/tests/components/netatmo/snapshots/test_button.ambr +++ b/tests/components/netatmo/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preferred position', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preferred position', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_camera.ambr b/tests/components/netatmo/snapshots/test_camera.ambr index 0b9bb4e948d..a1b05415334 100644 --- a/tests/components/netatmo/snapshots/test_camera.ambr +++ b/tests/components/netatmo/snapshots/test_camera.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_climate.ambr b/tests/components/netatmo/snapshots/test_climate.ambr index e5d5f477d34..c48b9beaa98 100644 --- a/tests/components/netatmo/snapshots/test_climate.ambr +++ b/tests/components/netatmo/snapshots/test_climate.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -111,6 +112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -195,6 +197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -278,6 +281,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -363,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_cover.ambr b/tests/components/netatmo/snapshots/test_cover.ambr index 1f83fcba615..ceda2bd0896 100644 --- a/tests/components/netatmo/snapshots/test_cover.ambr +++ b/tests/components/netatmo/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/netatmo/snapshots/test_fan.ambr b/tests/components/netatmo/snapshots/test_fan.ambr index 51136218734..20b0306a5a4 100644 --- a/tests/components/netatmo/snapshots/test_fan.ambr +++ b/tests/components/netatmo/snapshots/test_fan.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_light.ambr b/tests/components/netatmo/snapshots/test_light.ambr index 21fdc11842a..bd75e97c88f 100644 --- a/tests/components/netatmo/snapshots/test_light.ambr +++ b/tests/components/netatmo/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -139,6 +141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_select.ambr b/tests/components/netatmo/snapshots/test_select.ambr index f7c6303cead..3cd24f03a52 100644 --- a/tests/components/netatmo/snapshots/test_select.ambr +++ b/tests/components/netatmo/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_sensor.ambr b/tests/components/netatmo/snapshots/test_sensor.ambr index c0431a6449c..fc6a74e072d 100644 --- a/tests/components/netatmo/snapshots/test_sensor.ambr +++ b/tests/components/netatmo/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -146,6 +148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health index', 'options': dict({ }), 'original_device_class': , @@ -207,6 +210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -263,6 +267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure trend', 'options': dict({ }), 'original_device_class': None, @@ -371,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -424,6 +431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -481,6 +489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -532,6 +541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -585,6 +595,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -645,6 +656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -705,6 +717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health index', 'options': dict({ }), 'original_device_class': , @@ -764,6 +777,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -818,6 +832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -873,6 +888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure trend', 'options': dict({ }), 'original_device_class': None, @@ -922,6 +938,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -975,6 +992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1030,6 +1048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -1079,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -1132,6 +1152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1163,7 +1184,7 @@ 'state': '90', }) # --- -# name: test_entity[sensor.cold_water_none-entry] +# name: test_entity[sensor.cold_water-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1176,7 +1197,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.cold_water_none', + 'entity_id': 'sensor.cold_water', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1184,6 +1205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1198,21 +1220,21 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.cold_water_none-state] +# name: test_entity[sensor.cold_water-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Cold water None', }), 'context': , - 'entity_id': 'sensor.cold_water_none', + 'entity_id': 'sensor.cold_water', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'True', }) # --- -# name: test_entity[sensor.consumption_meter_none-entry] +# name: test_entity[sensor.consumption_meter-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1225,7 +1247,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.consumption_meter_none', + 'entity_id': 'sensor.consumption_meter', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1233,6 +1255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1247,14 +1270,14 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.consumption_meter_none-state] +# name: test_entity[sensor.consumption_meter-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Consumption meter None', }), 'context': , - 'entity_id': 'sensor.consumption_meter_none', + 'entity_id': 'sensor.consumption_meter', 'last_changed': , 'last_reported': , 'last_updated': , @@ -1284,6 +1307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1341,6 +1365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1372,7 +1397,7 @@ 'state': '67', }) # --- -# name: test_entity[sensor.ecocompteur_none-entry] +# name: test_entity[sensor.ecocompteur-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1385,7 +1410,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.ecocompteur_none', + 'entity_id': 'sensor.ecocompteur', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1393,6 +1418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1407,21 +1433,21 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.ecocompteur_none-state] +# name: test_entity[sensor.ecocompteur-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Écocompteur None', }), 'context': , - 'entity_id': 'sensor.ecocompteur_none', + 'entity_id': 'sensor.ecocompteur', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'unavailable', }) # --- -# name: test_entity[sensor.gas_none-entry] +# name: test_entity[sensor.gas-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -1434,7 +1460,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.gas_none', + 'entity_id': 'sensor.gas', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -1442,6 +1468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1456,14 +1483,14 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.gas_none-state] +# name: test_entity[sensor.gas-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Gas None', }), 'context': , - 'entity_id': 'sensor.gas_none', + 'entity_id': 'sensor.gas', 'last_changed': , 'last_reported': , 'last_updated': , @@ -1493,6 +1520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1555,6 +1583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust angle', 'options': dict({ }), 'original_device_class': , @@ -1611,6 +1640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1670,6 +1700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1726,6 +1757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1785,6 +1817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation last hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1844,6 +1877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1903,6 +1937,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1962,6 +1997,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -2018,6 +2054,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2077,6 +2114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2139,6 +2177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust angle', 'options': dict({ }), 'original_device_class': , @@ -2195,6 +2234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2254,6 +2294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2310,6 +2351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2369,6 +2411,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation last hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2428,6 +2471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2487,6 +2531,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2546,6 +2591,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -2602,6 +2648,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2661,6 +2708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2723,6 +2771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust angle', 'options': dict({ }), 'original_device_class': , @@ -2779,6 +2828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2838,6 +2888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2894,6 +2945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2953,6 +3005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation last hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3012,6 +3065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3071,6 +3125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3130,6 +3185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -3186,6 +3242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3222,7 +3279,7 @@ 'state': '15', }) # --- -# name: test_entity[sensor.hot_water_none-entry] +# name: test_entity[sensor.hot_water-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -3235,7 +3292,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.hot_water_none', + 'entity_id': 'sensor.hot_water', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -3243,6 +3300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3257,14 +3315,14 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.hot_water_none-state] +# name: test_entity[sensor.hot_water-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Hot water None', }), 'context': , - 'entity_id': 'sensor.hot_water_none', + 'entity_id': 'sensor.hot_water', 'last_changed': , 'last_reported': , 'last_updated': , @@ -3294,6 +3352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3356,6 +3415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -3418,6 +3478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health index', 'options': dict({ }), 'original_device_class': , @@ -3479,6 +3540,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -3535,6 +3597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3592,6 +3655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure trend', 'options': dict({ }), 'original_device_class': None, @@ -3643,6 +3707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -3696,6 +3761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3753,6 +3819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -3804,6 +3871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -3834,7 +3902,7 @@ 'state': 'Full', }) # --- -# name: test_entity[sensor.line_1_none-entry] +# name: test_entity[sensor.line_1-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -3847,7 +3915,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.line_1_none', + 'entity_id': 'sensor.line_1', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -3855,6 +3923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3869,21 +3938,21 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.line_1_none-state] +# name: test_entity[sensor.line_1-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Line 1 None', }), 'context': , - 'entity_id': 'sensor.line_1_none', + 'entity_id': 'sensor.line_1', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'True', }) # --- -# name: test_entity[sensor.line_2_none-entry] +# name: test_entity[sensor.line_2-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -3896,7 +3965,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.line_2_none', + 'entity_id': 'sensor.line_2', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -3904,6 +3973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3918,21 +3988,21 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.line_2_none-state] +# name: test_entity[sensor.line_2-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Line 2 None', }), 'context': , - 'entity_id': 'sensor.line_2_none', + 'entity_id': 'sensor.line_2', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'True', }) # --- -# name: test_entity[sensor.line_3_none-entry] +# name: test_entity[sensor.line_3-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -3945,7 +4015,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.line_3_none', + 'entity_id': 'sensor.line_3', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -3953,6 +4023,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3967,21 +4038,21 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.line_3_none-state] +# name: test_entity[sensor.line_3-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Line 3 None', }), 'context': , - 'entity_id': 'sensor.line_3_none', + 'entity_id': 'sensor.line_3', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'True', }) # --- -# name: test_entity[sensor.line_4_none-entry] +# name: test_entity[sensor.line_4-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -3994,7 +4065,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.line_4_none', + 'entity_id': 'sensor.line_4', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -4002,6 +4073,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -4016,21 +4088,21 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.line_4_none-state] +# name: test_entity[sensor.line_4-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Line 4 None', }), 'context': , - 'entity_id': 'sensor.line_4_none', + 'entity_id': 'sensor.line_4', 'last_changed': , 'last_reported': , 'last_updated': , 'state': 'True', }) # --- -# name: test_entity[sensor.line_5_none-entry] +# name: test_entity[sensor.line_5-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -4043,7 +4115,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.line_5_none', + 'entity_id': 'sensor.line_5', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -4051,6 +4123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -4065,14 +4138,14 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.line_5_none-state] +# name: test_entity[sensor.line_5-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Line 5 None', }), 'context': , - 'entity_id': 'sensor.line_5_none', + 'entity_id': 'sensor.line_5', 'last_changed': , 'last_reported': , 'last_updated': , @@ -4102,6 +4175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4164,6 +4238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4218,6 +4293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -4280,6 +4356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health index', 'options': dict({ }), 'original_device_class': , @@ -4341,6 +4418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -4397,6 +4475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4454,6 +4533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure trend', 'options': dict({ }), 'original_device_class': None, @@ -4505,6 +4585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -4558,6 +4639,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4615,6 +4697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -4666,6 +4749,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -4719,6 +4803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4781,6 +4866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -4843,6 +4929,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Health index', 'options': dict({ }), 'original_device_class': , @@ -4904,6 +4991,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -4960,6 +5048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5017,6 +5106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure trend', 'options': dict({ }), 'original_device_class': None, @@ -5068,6 +5158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -5121,6 +5212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5178,6 +5270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -5229,6 +5322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, @@ -5259,7 +5353,7 @@ 'state': 'High', }) # --- -# name: test_entity[sensor.prise_none-entry] +# name: test_entity[sensor.prise-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -5272,7 +5366,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.prise_none', + 'entity_id': 'sensor.prise', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -5280,6 +5374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -5294,14 +5389,14 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.prise_none-state] +# name: test_entity[sensor.prise-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Prise None', }), 'context': , - 'entity_id': 'sensor.prise_none', + 'entity_id': 'sensor.prise', 'last_changed': , 'last_reported': , 'last_updated': , @@ -5331,6 +5426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5365,7 +5461,7 @@ 'state': '0', }) # --- -# name: test_entity[sensor.total_none-entry] +# name: test_entity[sensor.total-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -5378,7 +5474,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': , - 'entity_id': 'sensor.total_none', + 'entity_id': 'sensor.total', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -5386,6 +5482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -5400,14 +5497,14 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[sensor.total_none-state] +# name: test_entity[sensor.total-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'attribution': 'Data provided by Netatmo', 'friendly_name': 'Total None', }), 'context': , - 'entity_id': 'sensor.total_none', + 'entity_id': 'sensor.total', 'last_changed': , 'last_reported': , 'last_updated': , @@ -5437,6 +5534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5491,6 +5589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5545,6 +5644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5607,6 +5707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5661,6 +5762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -5715,6 +5817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -5767,6 +5870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -5816,6 +5920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RF strength', 'options': dict({ }), 'original_device_class': None, @@ -5867,6 +5972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5922,6 +6028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -5973,6 +6080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -6027,6 +6135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -6081,6 +6190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -6133,6 +6243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -6182,6 +6293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RF strength', 'options': dict({ }), 'original_device_class': None, @@ -6233,6 +6345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6288,6 +6401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -6339,6 +6453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -6395,6 +6510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -6449,6 +6565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust angle', 'options': dict({ }), 'original_device_class': , @@ -6512,6 +6629,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust direction', 'options': dict({ }), 'original_device_class': , @@ -6574,6 +6692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gust strength', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6629,6 +6748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -6678,6 +6798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RF strength', 'options': dict({ }), 'original_device_class': None, @@ -6729,6 +6850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind angle', 'options': dict({ }), 'original_device_class': , @@ -6792,6 +6914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -6854,6 +6977,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6911,6 +7035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -6967,6 +7092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Noise', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7026,6 +7152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -7080,6 +7207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -7132,6 +7260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -7181,6 +7310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RF strength', 'options': dict({ }), 'original_device_class': None, @@ -7232,6 +7362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7287,6 +7418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -7336,6 +7468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure trend', 'options': dict({ }), 'original_device_class': None, @@ -7389,6 +7522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -7443,6 +7577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7500,6 +7635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation last hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7557,6 +7693,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7612,6 +7749,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -7661,6 +7799,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RF strength', 'options': dict({ }), 'original_device_class': None, @@ -7710,6 +7849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reachability', 'options': dict({ }), 'original_device_class': None, @@ -7763,6 +7903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7820,6 +7961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature trend', 'options': dict({ }), 'original_device_class': None, @@ -7871,6 +8013,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi strength', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/netatmo/snapshots/test_switch.ambr b/tests/components/netatmo/snapshots/test_switch.ambr index 3dd2d5658ac..cb0a36afa11 100644 --- a/tests/components/netatmo/snapshots/test_switch.ambr +++ b/tests/components/netatmo/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nextcloud/snapshots/test_binary_sensor.ambr b/tests/components/nextcloud/snapshots/test_binary_sensor.ambr index 1037147469f..6438fbfe029 100644 --- a/tests/components/nextcloud/snapshots/test_binary_sensor.ambr +++ b/tests/components/nextcloud/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avatars enabled', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Debug enabled', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filelocking enabled', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT active', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT enabled', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Previews enabled', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nextcloud/snapshots/test_sensor.ambr b/tests/components/nextcloud/snapshots/test_sensor.ambr index e425716b213..efaec6953c7 100644 --- a/tests/components/nextcloud/snapshots/test_sensor.ambr +++ b/tests/components/nextcloud/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of active users last 5 minutes', 'options': dict({ }), 'original_device_class': None, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of active users last day', 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of active users last hour', 'options': dict({ }), 'original_device_class': None, @@ -175,6 +178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of files', 'options': dict({ }), 'original_device_class': None, @@ -226,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of group shares', 'options': dict({ }), 'original_device_class': None, @@ -277,6 +282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of link shares', 'options': dict({ }), 'original_device_class': None, @@ -328,6 +334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of local storages', 'options': dict({ }), 'original_device_class': None, @@ -379,6 +386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of mail shares', 'options': dict({ }), 'original_device_class': None, @@ -430,6 +438,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of other storages', 'options': dict({ }), 'original_device_class': None, @@ -481,6 +490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of passwordless link shares', 'options': dict({ }), 'original_device_class': None, @@ -532,6 +542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of room shares', 'options': dict({ }), 'original_device_class': None, @@ -583,6 +594,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of shares', 'options': dict({ }), 'original_device_class': None, @@ -634,6 +646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of shares received', 'options': dict({ }), 'original_device_class': None, @@ -685,6 +698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of shares sent', 'options': dict({ }), 'original_device_class': None, @@ -736,6 +750,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of storages', 'options': dict({ }), 'original_device_class': None, @@ -787,6 +802,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of storages at home', 'options': dict({ }), 'original_device_class': None, @@ -838,6 +854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of user', 'options': dict({ }), 'original_device_class': None, @@ -889,6 +906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amount of user shares', 'options': dict({ }), 'original_device_class': None, @@ -940,6 +958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apps installed', 'options': dict({ }), 'original_device_class': None, @@ -991,6 +1010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache expunges', 'options': dict({ }), 'original_device_class': None, @@ -1040,6 +1060,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache memory', 'options': dict({ }), 'original_device_class': None, @@ -1088,6 +1109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache memory size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1146,6 +1168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache number of entries', 'options': dict({ }), 'original_device_class': None, @@ -1197,6 +1220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache number of hits', 'options': dict({ }), 'original_device_class': None, @@ -1248,6 +1272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache number of inserts', 'options': dict({ }), 'original_device_class': None, @@ -1299,6 +1324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache number of misses', 'options': dict({ }), 'original_device_class': None, @@ -1350,6 +1376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache number of slots', 'options': dict({ }), 'original_device_class': None, @@ -1399,6 +1426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache start time', 'options': dict({ }), 'original_device_class': , @@ -1448,6 +1476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache TTL', 'options': dict({ }), 'original_device_class': None, @@ -1496,6 +1525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU load last 15 minutes', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1548,6 +1578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU load last 1 minute', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1600,6 +1631,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU load last 5 minutes', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1652,6 +1684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Database size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1708,6 +1741,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Database type', 'options': dict({ }), 'original_device_class': None, @@ -1756,6 +1790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Database version', 'options': dict({ }), 'original_device_class': None, @@ -1804,6 +1839,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1860,6 +1896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1916,6 +1953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free swap memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1972,6 +2010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Interned buffer size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2028,6 +2067,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Interned free memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2086,6 +2126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Interned number of strings', 'options': dict({ }), 'original_device_class': None, @@ -2135,6 +2176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Interned used memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2191,6 +2233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT buffer free', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2247,6 +2290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT buffer size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2303,6 +2347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT kind', 'options': dict({ }), 'original_device_class': None, @@ -2351,6 +2396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT opt flags', 'options': dict({ }), 'original_device_class': None, @@ -2399,6 +2445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'JIT opt level', 'options': dict({ }), 'original_device_class': None, @@ -2449,6 +2496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache blacklist miss ratio', 'options': dict({ }), 'original_device_class': None, @@ -2501,6 +2549,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache blacklist misses', 'options': dict({ }), 'original_device_class': None, @@ -2552,6 +2601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache cached keys', 'options': dict({ }), 'original_device_class': None, @@ -2603,6 +2653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache cached scripts', 'options': dict({ }), 'original_device_class': None, @@ -2652,6 +2703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache current wasted percentage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2704,6 +2756,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache free memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2762,6 +2815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache hash restarts', 'options': dict({ }), 'original_device_class': None, @@ -2811,6 +2865,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache hit rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2865,6 +2920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache hits', 'options': dict({ }), 'original_device_class': None, @@ -2914,6 +2970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache last restart time', 'options': dict({ }), 'original_device_class': , @@ -2965,6 +3022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache manual restarts', 'options': dict({ }), 'original_device_class': None, @@ -3016,6 +3074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache max cached keys', 'options': dict({ }), 'original_device_class': None, @@ -3067,6 +3126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache misses', 'options': dict({ }), 'original_device_class': None, @@ -3118,6 +3178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache out of memory restarts', 'options': dict({ }), 'original_device_class': None, @@ -3167,6 +3228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache start time', 'options': dict({ }), 'original_device_class': , @@ -3216,6 +3278,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache used memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3272,6 +3335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opcache wasted memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3328,6 +3392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PHP max execution time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3381,6 +3446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PHP memory limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3437,6 +3503,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PHP upload maximum filesize', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3493,6 +3560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PHP version', 'options': dict({ }), 'original_device_class': None, @@ -3541,6 +3609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA available memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3599,6 +3668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA number of segments', 'options': dict({ }), 'original_device_class': None, @@ -3648,6 +3718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA segment size', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3704,6 +3775,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System memcache distributed', 'options': dict({ }), 'original_device_class': None, @@ -3752,6 +3824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System memcache local', 'options': dict({ }), 'original_device_class': None, @@ -3800,6 +3873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System memcache locking', 'options': dict({ }), 'original_device_class': None, @@ -3848,6 +3922,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System theme', 'options': dict({ }), 'original_device_class': None, @@ -3896,6 +3971,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'System version', 'options': dict({ }), 'original_device_class': None, @@ -3944,6 +4020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4000,6 +4077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total swap memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4058,6 +4136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Updates available', 'options': dict({ }), 'original_device_class': None, @@ -4107,6 +4186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Webserver', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nextcloud/snapshots/test_update.ambr b/tests/components/nextcloud/snapshots/test_update.ambr index 0a3ae568a44..9e709582b4e 100644 --- a/tests/components/nextcloud/snapshots/test_update.ambr +++ b/tests/components/nextcloud/snapshots/test_update.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_async_setup_entry[update.my_nc_url_local_none-entry] +# name: test_async_setup_entry[update.my_nc_url_local-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -12,7 +12,7 @@ 'disabled_by': None, 'domain': 'update', 'entity_category': , - 'entity_id': 'update.my_nc_url_local_none', + 'entity_id': 'update.my_nc_url_local', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -34,7 +35,7 @@ 'unit_of_measurement': None, }) # --- -# name: test_async_setup_entry[update.my_nc_url_local_none-state] +# name: test_async_setup_entry[update.my_nc_url_local-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'auto_update': False, @@ -52,7 +53,7 @@ 'update_percentage': None, }), 'context': , - 'entity_id': 'update.my_nc_url_local_none', + 'entity_id': 'update.my_nc_url_local', 'last_changed': , 'last_reported': , 'last_updated': , diff --git a/tests/components/nextdns/snapshots/test_binary_sensor.ambr b/tests/components/nextdns/snapshots/test_binary_sensor.ambr index f8a05ad00ad..059822b82c9 100644 --- a/tests/components/nextdns/snapshots/test_binary_sensor.ambr +++ b/tests/components/nextdns/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device connection status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device profile connection status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/nextdns/snapshots/test_button.ambr b/tests/components/nextdns/snapshots/test_button.ambr index d416f9ef47e..460cf13e8d6 100644 --- a/tests/components/nextdns/snapshots/test_button.ambr +++ b/tests/components/nextdns/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clear logs', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nextdns/snapshots/test_sensor.ambr b/tests/components/nextdns/snapshots/test_sensor.ambr index 6aa061d1a9a..ca768a08f6d 100644 --- a/tests/components/nextdns/snapshots/test_sensor.ambr +++ b/tests/components/nextdns/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-HTTP/3 queries', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-HTTP/3 queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-HTTPS queries', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-HTTPS queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-QUIC queries', 'options': dict({ }), 'original_device_class': None, @@ -282,6 +287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-QUIC queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -334,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-TLS queries', 'options': dict({ }), 'original_device_class': None, @@ -386,6 +393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS-over-TLS queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -438,6 +446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries', 'options': dict({ }), 'original_device_class': None, @@ -490,6 +499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries blocked', 'options': dict({ }), 'original_device_class': None, @@ -542,6 +552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries blocked ratio', 'options': dict({ }), 'original_device_class': None, @@ -594,6 +605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS queries relayed', 'options': dict({ }), 'original_device_class': None, @@ -646,6 +658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNSSEC not validated queries', 'options': dict({ }), 'original_device_class': None, @@ -698,6 +711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNSSEC validated queries', 'options': dict({ }), 'original_device_class': None, @@ -750,6 +764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNSSEC validated queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -802,6 +817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Encrypted queries', 'options': dict({ }), 'original_device_class': None, @@ -854,6 +870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Encrypted queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -906,6 +923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IPv4 queries', 'options': dict({ }), 'original_device_class': None, @@ -958,6 +976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IPv6 queries', 'options': dict({ }), 'original_device_class': None, @@ -1010,6 +1029,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IPv6 queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -1062,6 +1082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TCP queries', 'options': dict({ }), 'original_device_class': None, @@ -1114,6 +1135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TCP queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -1166,6 +1188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UDP queries', 'options': dict({ }), 'original_device_class': None, @@ -1218,6 +1241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UDP queries ratio', 'options': dict({ }), 'original_device_class': None, @@ -1270,6 +1294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Unencrypted queries', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nextdns/snapshots/test_switch.ambr b/tests/components/nextdns/snapshots/test_switch.ambr index 74bf7e27b43..4a8e7cf744c 100644 --- a/tests/components/nextdns/snapshots/test_switch.ambr +++ b/tests/components/nextdns/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AI-Driven threat detection', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow affiliate & tracking links', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Anonymized EDNS client subnet', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block 9GAG', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Amazon', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block BeReal', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Blizzard', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block bypass methods', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block ChatGPT', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block child sexual abuse material', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Dailymotion', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block dating', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Discord', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block disguised third-party trackers', 'options': dict({ }), 'original_device_class': None, @@ -692,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Disney Plus', 'options': dict({ }), 'original_device_class': None, @@ -740,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block dynamic DNS hostnames', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block eBay', 'options': dict({ }), 'original_device_class': None, @@ -836,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Facebook', 'options': dict({ }), 'original_device_class': None, @@ -884,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Fortnite', 'options': dict({ }), 'original_device_class': None, @@ -932,6 +951,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block gambling', 'options': dict({ }), 'original_device_class': None, @@ -980,6 +1000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Google Chat', 'options': dict({ }), 'original_device_class': None, @@ -1028,6 +1049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block HBO Max', 'options': dict({ }), 'original_device_class': None, @@ -1076,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Hulu', 'options': dict({ }), 'original_device_class': None, @@ -1124,6 +1147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Imgur', 'options': dict({ }), 'original_device_class': None, @@ -1172,6 +1196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Instagram', 'options': dict({ }), 'original_device_class': None, @@ -1220,6 +1245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block League of Legends', 'options': dict({ }), 'original_device_class': None, @@ -1268,6 +1294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Mastodon', 'options': dict({ }), 'original_device_class': None, @@ -1316,6 +1343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Messenger', 'options': dict({ }), 'original_device_class': None, @@ -1364,6 +1392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Minecraft', 'options': dict({ }), 'original_device_class': None, @@ -1412,6 +1441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Netflix', 'options': dict({ }), 'original_device_class': None, @@ -1460,6 +1490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block newly registered domains', 'options': dict({ }), 'original_device_class': None, @@ -1508,6 +1539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block online gaming', 'options': dict({ }), 'original_device_class': None, @@ -1556,6 +1588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block page', 'options': dict({ }), 'original_device_class': None, @@ -1604,6 +1637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block parked domains', 'options': dict({ }), 'original_device_class': None, @@ -1652,6 +1686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Pinterest', 'options': dict({ }), 'original_device_class': None, @@ -1700,6 +1735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block piracy', 'options': dict({ }), 'original_device_class': None, @@ -1748,6 +1784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block PlayStation Network', 'options': dict({ }), 'original_device_class': None, @@ -1796,6 +1833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block porn', 'options': dict({ }), 'original_device_class': None, @@ -1844,6 +1882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Prime Video', 'options': dict({ }), 'original_device_class': None, @@ -1892,6 +1931,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Reddit', 'options': dict({ }), 'original_device_class': None, @@ -1940,6 +1980,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Roblox', 'options': dict({ }), 'original_device_class': None, @@ -1988,6 +2029,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Signal', 'options': dict({ }), 'original_device_class': None, @@ -2036,6 +2078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Skype', 'options': dict({ }), 'original_device_class': None, @@ -2084,6 +2127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Snapchat', 'options': dict({ }), 'original_device_class': None, @@ -2132,6 +2176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block social networks', 'options': dict({ }), 'original_device_class': None, @@ -2180,6 +2225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Spotify', 'options': dict({ }), 'original_device_class': None, @@ -2228,6 +2274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Steam', 'options': dict({ }), 'original_device_class': None, @@ -2276,6 +2323,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Telegram', 'options': dict({ }), 'original_device_class': None, @@ -2324,6 +2372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block TikTok', 'options': dict({ }), 'original_device_class': None, @@ -2372,6 +2421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Tinder', 'options': dict({ }), 'original_device_class': None, @@ -2420,6 +2470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Tumblr', 'options': dict({ }), 'original_device_class': None, @@ -2468,6 +2519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Twitch', 'options': dict({ }), 'original_device_class': None, @@ -2516,6 +2568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block video streaming', 'options': dict({ }), 'original_device_class': None, @@ -2564,6 +2617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Vimeo', 'options': dict({ }), 'original_device_class': None, @@ -2612,6 +2666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block VK', 'options': dict({ }), 'original_device_class': None, @@ -2660,6 +2715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block WhatsApp', 'options': dict({ }), 'original_device_class': None, @@ -2708,6 +2764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block X (formerly Twitter)', 'options': dict({ }), 'original_device_class': None, @@ -2756,6 +2813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Xbox Network', 'options': dict({ }), 'original_device_class': None, @@ -2804,6 +2862,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block YouTube', 'options': dict({ }), 'original_device_class': None, @@ -2852,6 +2911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Zoom', 'options': dict({ }), 'original_device_class': None, @@ -2900,6 +2960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass age verification', 'options': dict({ }), 'original_device_class': None, @@ -2948,6 +3009,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cache boost', 'options': dict({ }), 'original_device_class': None, @@ -2996,6 +3058,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CNAME flattening', 'options': dict({ }), 'original_device_class': None, @@ -3044,6 +3107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cryptojacking protection', 'options': dict({ }), 'original_device_class': None, @@ -3092,6 +3156,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DNS rebinding protection', 'options': dict({ }), 'original_device_class': None, @@ -3140,6 +3205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Domain generation algorithms protection', 'options': dict({ }), 'original_device_class': None, @@ -3188,6 +3254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Force SafeSearch', 'options': dict({ }), 'original_device_class': None, @@ -3236,6 +3303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Force YouTube restricted mode', 'options': dict({ }), 'original_device_class': None, @@ -3284,6 +3352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Google safe browsing', 'options': dict({ }), 'original_device_class': None, @@ -3332,6 +3401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IDN homograph attacks protection', 'options': dict({ }), 'original_device_class': None, @@ -3380,6 +3450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Logs', 'options': dict({ }), 'original_device_class': None, @@ -3428,6 +3499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Threat intelligence feeds', 'options': dict({ }), 'original_device_class': None, @@ -3476,6 +3548,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Typosquatting protection', 'options': dict({ }), 'original_device_class': None, @@ -3524,6 +3597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Web3', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nibe_heatpump/snapshots/test_binary_sensor.ambr b/tests/components/nibe_heatpump/snapshots/test_binary_sensor.ambr index 37dd7a8679c..721fe41a642 100644 --- a/tests/components/nibe_heatpump/snapshots/test_binary_sensor.ambr +++ b/tests/components/nibe_heatpump/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nibe_heatpump/snapshots/test_switch.ambr b/tests/components/nibe_heatpump/snapshots/test_switch.ambr index 01f35bd8a54..e2d7292a33c 100644 --- a/tests/components/nibe_heatpump/snapshots/test_switch.ambr +++ b/tests/components/nibe_heatpump/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nice_go/snapshots/test_cover.ambr b/tests/components/nice_go/snapshots/test_cover.ambr index 31ae154422d..2dac0e5795a 100644 --- a/tests/components/nice_go/snapshots/test_cover.ambr +++ b/tests/components/nice_go/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/nice_go/snapshots/test_light.ambr b/tests/components/nice_go/snapshots/test_light.ambr index ffb5b8bff8d..aee7d6d0d46 100644 --- a/tests/components/nice_go/snapshots/test_light.ambr +++ b/tests/components/nice_go/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/niko_home_control/snapshots/test_climate.ambr b/tests/components/niko_home_control/snapshots/test_climate.ambr index abd5b5306aa..33e9f5fcf60 100644 --- a/tests/components/niko_home_control/snapshots/test_climate.ambr +++ b/tests/components/niko_home_control/snapshots/test_climate.ambr @@ -36,6 +36,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/niko_home_control/snapshots/test_cover.ambr b/tests/components/niko_home_control/snapshots/test_cover.ambr index dc7cb0f4bce..ea91d6da772 100644 --- a/tests/components/niko_home_control/snapshots/test_cover.ambr +++ b/tests/components/niko_home_control/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/niko_home_control/snapshots/test_light.ambr b/tests/components/niko_home_control/snapshots/test_light.ambr index 85f07dfed37..1bf4103f570 100644 --- a/tests/components/niko_home_control/snapshots/test_light.ambr +++ b/tests/components/niko_home_control/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/niko_home_control/snapshots/test_scene.ambr b/tests/components/niko_home_control/snapshots/test_scene.ambr index 6887b1b373e..1469d5db9c2 100644 --- a/tests/components/niko_home_control/snapshots/test_scene.ambr +++ b/tests/components/niko_home_control/snapshots/test_scene.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nina/__init__.py b/tests/components/nina/__init__.py index 702bd78715b..1ea7d130b65 100644 --- a/tests/components/nina/__init__.py +++ b/tests/components/nina/__init__.py @@ -1,47 +1,30 @@ """Tests for the Nina integration.""" -import json -from typing import Any +from copy import deepcopy +from unittest.mock import AsyncMock -from tests.common import load_fixture +from pynina import Warning + +from homeassistant.components.nina.const import CONF_REGIONS +from homeassistant.config_entries import ConfigEntryState +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry -def mocked_request_function(url: str) -> dict[str, Any]: - """Mock of the request function.""" - dummy_response: dict[str, Any] = json.loads( - load_fixture("sample_warnings.json", "nina") - ) +async def setup_platform( + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: + """Set up the NINA platform.""" + mock_nina_class.warnings = { + region: deepcopy(nina_warnings) + for region in config_entry.data.get(CONF_REGIONS, {}) + } - dummy_response_details: dict[str, Any] = json.loads( - load_fixture("sample_warning_details.json", "nina") - ) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() - dummy_response_regions: dict[str, Any] = json.loads( - load_fixture("sample_regions.json", "nina") - ) - - dummy_response_labels: dict[str, Any] = json.loads( - load_fixture("sample_labels.json", "nina") - ) - - if "https://warnung.bund.de/api31/dashboard/" in url: # codespell:ignore bund - return dummy_response - - if ( - "https://warnung.bund.de/api/appdata/gsb/labels/de_labels.json" # codespell:ignore bund - in url - ): - return dummy_response_labels - - if ( - url - == "https://www.xrepository.de/api/xrepository/urn:de:bund:destatis:bevoelkerungsstatistik:schluessel:rs_2021-07-31/download/Regionalschl_ssel_2021-07-31.json" # codespell:ignore bund - ): - return dummy_response_regions - - warning_id = url.replace( - "https://warnung.bund.de/api31/warnings/", # codespell:ignore bund - "", - ).replace(".json", "") - - return dummy_response_details[warning_id] + assert config_entry.state is ConfigEntryState.LOADED diff --git a/tests/components/nina/conftest.py b/tests/components/nina/conftest.py index 9c58e8c6632..53384452dda 100644 --- a/tests/components/nina/conftest.py +++ b/tests/components/nina/conftest.py @@ -4,6 +4,7 @@ from collections.abc import Generator from copy import deepcopy from unittest.mock import AsyncMock, patch +from pynina import Warning import pytest from homeassistant.components.nina.const import DOMAIN @@ -11,7 +12,11 @@ from homeassistant.core import HomeAssistant from .const import DUMMY_CONFIG_ENTRY -from tests.common import MockConfigEntry +from tests.common import ( + MockConfigEntry, + load_json_array_fixture, + load_json_object_fixture, +) @pytest.fixture @@ -37,3 +42,32 @@ def mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: config_entry.add_to_hass(hass) return config_entry + + +@pytest.fixture +def mock_nina_class(nina_region_codes: dict[str, str]) -> Generator[AsyncMock]: + """Fixture to mock the NINA class.""" + with ( + patch( + "homeassistant.components.nina.config_flow.Nina", autospec=True + ) as mock_nina, + patch("homeassistant.components.nina.coordinator.Nina", new=mock_nina), + ): + nina = mock_nina.return_value + nina.get_all_regional_codes.return_value = nina_region_codes + + yield nina + + +@pytest.fixture +def nina_region_codes() -> dict[str, str]: + """Provide region codes.""" + return load_json_object_fixture("regions.json", DOMAIN) + + +@pytest.fixture +def nina_warnings() -> list[Warning]: + """Provide sample warnings.""" + raw_data = load_json_array_fixture("warnings.json", DOMAIN) + + return [Warning(**w) for w in raw_data] diff --git a/tests/components/nina/fixtures/regions.json b/tests/components/nina/fixtures/regions.json new file mode 100644 index 00000000000..797726fa8ea --- /dev/null +++ b/tests/components/nina/fixtures/regions.json @@ -0,0 +1,11088 @@ +{ + "Flensburg, Stadt": "010010000000", + "Kiel, Landeshauptstadt": "010020000000", + "Lübeck, Hansestadt": "010030000000", + "Neumünster, Stadt": "010040000000", + "Brunsbüttel, Stadt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Heide, Stadt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Averlak (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Brickeln (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Buchholz (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Burg (Dithmarschen) (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Dingen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Eddelak (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Eggstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Frestedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Großenrade (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hochdonn (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Kuden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Quickborn (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Sankt Michaelisdonn (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Süderhastedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Diekhusen-Fahrstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Friedrichskoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Helse (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Kaiser-Wilhelm-Koog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Kronprinzenkoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Marne, Stadt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Marnerdeich (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Neufeld (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Neufelderkoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Ramhusen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Schmedeswurth (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Trennewurth (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Volsemenhusen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Barkenholm (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Bergewöhrden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Dellstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Delve (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Dörpling (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Fedderingen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Gaushorn (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Glüsing (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Groven (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hemme (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hennstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hövede (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hollingstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Karolinenkoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Kleve (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Krempel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Lehe (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Linden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Lunden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Norderheistedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Pahlen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Rehm-Flehde-Bargen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Sankt Annen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Schalkholz (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Schlichting (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Tellingstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Tielenhemme (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wallen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Welmbüttel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Westerborstel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wiemerstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wrohm (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Süderdorf (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Süderheistedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hemmingstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Lieth (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Lohe-Rickelshof (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Neuenkirchen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Norderwöhrden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Nordhastedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Ostrohe (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Stelle-Wittenwurth (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wöhrden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Weddingstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wesseln (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Albersdorf (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Arkebek (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Bargenstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Barlt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Bunsoh (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Busenwurth (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Elpersbüttel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Epenwöhrden (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Gudendorf (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Immenstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Krumstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Meldorf, Stadt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Nindorf (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Odderade (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Offenbüttel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Osterrade (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Sarzbüttel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Schafstedt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Schrum (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wennbüttel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Windbergen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wolmersdorf (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Nordermeldorf (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Tensbüttel-Röst (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Büsum (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Büsumer Deichhausen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Friedrichsgabekoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hedwigenkoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hellschen-Heringsand-Unterschaar (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Hillgroven (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Norddeich (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Oesterdeichstrich (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Reinsbüttel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Schülp (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Strübbel (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Süderdeich (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Warwerort (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wesselburen, Stadt (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wesselburener Deichhausen (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Wesselburenerkoog (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Westerdeichstrich (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Oesterwurth (Dithmarschen - Schleswig-Holstein)": "010510000000", + "Geesthacht, Stadt (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Lauenburg/ Elbe, Stadt (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Mölln, Stadt (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Ratzeburg, Stadt (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schwarzenbek, Stadt (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Wentorf bei Hamburg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Behlendorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Berkenthin (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Bliestorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Düchelsdorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Göldenitz (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kastorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Klempau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Krummesse (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Niendorf bei Berkenthin (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Rondeshagen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Sierksrade (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Alt-Mölln (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Bälau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Borstorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Breitenfelde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Grambek (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Hornbek (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Lehmrade (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Niendorf/ Stecknitz (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schretstaken (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Talkau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Woltersdorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Besenthal (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Bröthen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Büchen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Fitzen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Göttin (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Gudow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Güster (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Klein Pampau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Langenlehsten (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Müssen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Roseburg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schulendorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Siebeneichen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Tramm (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Witzeeze (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Aumühle (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Börnsen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Dassendorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Escheburg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Hamwarde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Hohenhorn (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kröppelshagen-Fahrendorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Wiershop (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Wohltorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Worth (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Basedow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Buchhorst (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Dalldorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Juliusburg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Krüzen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Krukow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Lanze (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Lütau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schnakenbek (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Wangelau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Albsfelde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Bäk (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Brunsmark (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Buchholz (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Einhaus (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Fredeburg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Giesensdorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Groß Disnack (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Groß Grönau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Groß Sarau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Harmsdorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Hollenbek (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Horst (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kittlitz (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Klein Zecher (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kulpin (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Mechow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Mustin (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Pogeez (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Römnitz (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Salem (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schmilau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Seedorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Sterley (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Ziethen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Basthorst (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Brunstorf (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Dahmker (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Elmenhorst (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Fuhlenhagen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Grabau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Groß Pampau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Grove (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Gülzow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Hamfelde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Havekost (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kankelau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kasseburg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Köthel (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kollow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kuddewörde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Möhnsen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Mühlenrade (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Sahms (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Duvensee (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Grinau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Groß Boden (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Groß Schenkenberg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Klinkrade (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Koberg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Kühsen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Labenz (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Lankau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Linau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Lüchow (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Nusse (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Panten (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Poggensee (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Ritzerau (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Sandesneben (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schiphorst (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schönberg (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Schürensöhlen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Siebenbäumen (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Sirksfelde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Steinhorst (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Stubben (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Walksfelde (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Wentorf (Amt Sandesneben) (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Sachsenwald (Forstgutsbez.),gemfr.Geb. (Herzogtum Lauenburg - Schleswig-Holstein)": "010530000000", + "Friedrichstadt, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Husum, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Reußenköge (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Tönning, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Sylt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Garding, Kirchspiel (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Garding, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Grothusenkoog (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Katharinenheerd (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Kotzenbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Norderfriedrichskoog (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Oldenswort (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Osterhever (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Poppenbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Sankt Peter-Ording (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Tating (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Tetenbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Tümlauer Koog (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Vollerwiek (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Welt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Westerhever (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Hörnum (Sylt) (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Kampen (Sylt) (Nordfriesland - Schleswig-Holstein)": "010540000000", + "List auf Sylt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wenningstedt-Braderup (Sylt) (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ahrenviöl (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ahrenviölfeld (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Behrendorf (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bondelum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Haselund (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Immenstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Löwenstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Norstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Oster-Ohrstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Schwesing (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Sollwitt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Viöl (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wester-Ohrstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Gröde (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Hallig Hooge (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Langeneß (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Pellworm (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Alkersum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Borgsum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Dunsum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Midlum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Nebel (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Nieblum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Norddorf auf Amrum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Oevenum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Oldsum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Süderende (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Utersum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Witsum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wittdün auf Amrum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wrixum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wyk auf Föhr, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Achtrup (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Aventoft (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bosbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Braderup (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bramstedtlund (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Dagebüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ellhöft (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Friedrich-Wilhelm-Lübke-Koog (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Holm (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Humptrup (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Karlum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Klanxbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Klixbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ladelund (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Leck (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Lexgaard (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Neukirchen (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Niebüll, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Risum-Lindholm (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Rodenäs (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Sprakebüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Stadum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Stedesand (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Süderlügum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Tinningstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Uphusum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Westre (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Galmsbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Emmelsbüll-Horsbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Enge-Sande (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Arlewatt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Drage (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Elisabeth-Sophien-Koog (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Fresendelf (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Hattstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Hattstedtermarsch (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Horstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Hude (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Koldenbüttel (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Mildstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Nordstrand (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Oldersbek (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Olderup (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ostenfeld (Husum) (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ramstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Rantrum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Schwabstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Seeth (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Simonsberg (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Süderhöft (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Südermarsch (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Uelvesbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Winnert (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wisch (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wittbek (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Witzwort (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Wobbenbüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ahrenshöft (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Almdorf (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bargum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bohmstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bordelum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Bredstedt, Stadt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Breklum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Drelsdorf (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Goldebek (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Goldelund (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Högel (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Joldelund (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Kolkerheide (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Langenhorn (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Lütjenholm (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ockholm (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Sönnebüll (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Struckum (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Vollstedt (Nordfriesland - Schleswig-Holstein)": "010540000000", + "Ahrensbök (Ostholstein - Schleswig-Holstein)": "010550000000", + "Bad Schwartau, Stadt (Ostholstein - Schleswig-Holstein)": "010550000000", + "Bosau (Ostholstein - Schleswig-Holstein)": "010550000000", + "Dahme (Ostholstein - Schleswig-Holstein)": "010550000000", + "Eutin, Stadt (Ostholstein - Schleswig-Holstein)": "010550000000", + "Grömitz (Ostholstein - Schleswig-Holstein)": "010550000000", + "Grube (Ostholstein - Schleswig-Holstein)": "010550000000", + "Heiligenhafen, Stadt (Ostholstein - Schleswig-Holstein)": "010550000000", + "Kellenhusen (Ostsee) (Ostholstein - Schleswig-Holstein)": "010550000000", + "Malente (Ostholstein - Schleswig-Holstein)": "010550000000", + "Neustadt in Holstein, Stadt (Ostholstein - Schleswig-Holstein)": "010550000000", + "Oldenburg in Holstein, Stadt (Ostholstein - Schleswig-Holstein)": "010550000000", + "Ratekau (Ostholstein - Schleswig-Holstein)": "010550000000", + "Stockelsdorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Süsel (Ostholstein - Schleswig-Holstein)": "010550000000", + "Timmendorfer Strand (Ostholstein - Schleswig-Holstein)": "010550000000", + "Scharbeutz (Ostholstein - Schleswig-Holstein)": "010550000000", + "Fehmarn, Stadt (Ostholstein - Schleswig-Holstein)": "010550000000", + "Göhl (Ostholstein - Schleswig-Holstein)": "010550000000", + "Gremersdorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Großenbrode (Ostholstein - Schleswig-Holstein)": "010550000000", + "Heringsdorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Neukirchen (Ostholstein - Schleswig-Holstein)": "010550000000", + "Wangels (Ostholstein - Schleswig-Holstein)": "010550000000", + "Beschendorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Damlos (Ostholstein - Schleswig-Holstein)": "010550000000", + "Harmsdorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Kabelhorst (Ostholstein - Schleswig-Holstein)": "010550000000", + "Lensahn (Ostholstein - Schleswig-Holstein)": "010550000000", + "Manhagen (Ostholstein - Schleswig-Holstein)": "010550000000", + "Riepsdorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Altenkrempe (Ostholstein - Schleswig-Holstein)": "010550000000", + "Kasseedorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Schashagen (Ostholstein - Schleswig-Holstein)": "010550000000", + "Schönwalde am Bungsberg (Ostholstein - Schleswig-Holstein)": "010550000000", + "Sierksdorf (Ostholstein - Schleswig-Holstein)": "010550000000", + "Barmstedt, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Bönningstedt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Elmshorn, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Halstenbek (Pinneberg - Schleswig-Holstein)": "010560000000", + "Hasloh (Pinneberg - Schleswig-Holstein)": "010560000000", + "Helgoland (Pinneberg - Schleswig-Holstein)": "010560000000", + "Pinneberg, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Quickborn, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Rellingen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Schenefeld, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Tornesch, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Uetersen, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Wedel, Stadt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Klein Nordende (Pinneberg - Schleswig-Holstein)": "010560000000", + "Klein Offenseth-Sparrieshoop (Pinneberg - Schleswig-Holstein)": "010560000000", + "Kölln-Reisiek (Pinneberg - Schleswig-Holstein)": "010560000000", + "Seester (Pinneberg - Schleswig-Holstein)": "010560000000", + "Raa-Besenbek (Pinneberg - Schleswig-Holstein)": "010560000000", + "Seestermühe (Pinneberg - Schleswig-Holstein)": "010560000000", + "Seeth-Ekholt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Bokel (Pinneberg - Schleswig-Holstein)": "010560000000", + "Brande-Hörnerkirchen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Osterhorn (Pinneberg - Schleswig-Holstein)": "010560000000", + "Westerhorn (Pinneberg - Schleswig-Holstein)": "010560000000", + "Bevern (Pinneberg - Schleswig-Holstein)": "010560000000", + "Bilsen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Bokholt-Hanredder (Pinneberg - Schleswig-Holstein)": "010560000000", + "Bullenkuhlen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Ellerhoop (Pinneberg - Schleswig-Holstein)": "010560000000", + "Groß Offenseth-Aspern (Pinneberg - Schleswig-Holstein)": "010560000000", + "Heede (Pinneberg - Schleswig-Holstein)": "010560000000", + "Hemdingen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Langeln (Pinneberg - Schleswig-Holstein)": "010560000000", + "Lutzhorn (Pinneberg - Schleswig-Holstein)": "010560000000", + "Borstel-Hohenraden (Pinneberg - Schleswig-Holstein)": "010560000000", + "Ellerbek (Pinneberg - Schleswig-Holstein)": "010560000000", + "Kummerfeld (Pinneberg - Schleswig-Holstein)": "010560000000", + "Prisdorf (Pinneberg - Schleswig-Holstein)": "010560000000", + "Tangstedt (Pinneberg - Schleswig-Holstein)": "010560000000", + "Appen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Groß Nordende (Pinneberg - Schleswig-Holstein)": "010560000000", + "Haselau (Pinneberg - Schleswig-Holstein)": "010560000000", + "Haseldorf (Pinneberg - Schleswig-Holstein)": "010560000000", + "Heidgraben (Pinneberg - Schleswig-Holstein)": "010560000000", + "Heist (Pinneberg - Schleswig-Holstein)": "010560000000", + "Hetlingen (Pinneberg - Schleswig-Holstein)": "010560000000", + "Holm (Pinneberg - Schleswig-Holstein)": "010560000000", + "Moorrege (Pinneberg - Schleswig-Holstein)": "010560000000", + "Neuendeich (Pinneberg - Schleswig-Holstein)": "010560000000", + "Ascheberg (Holstein) (Plön - Schleswig-Holstein)": "010570000000", + "Bönebüttel (Plön - Schleswig-Holstein)": "010570000000", + "Bösdorf (Plön - Schleswig-Holstein)": "010570000000", + "Plön, Stadt (Plön - Schleswig-Holstein)": "010570000000", + "Preetz, Stadt (Plön - Schleswig-Holstein)": "010570000000", + "Schwentinental, Stadt (Plön - Schleswig-Holstein)": "010570000000", + "Behrensdorf (Ostsee) (Plön - Schleswig-Holstein)": "010570000000", + "Blekendorf (Plön - Schleswig-Holstein)": "010570000000", + "Dannau (Plön - Schleswig-Holstein)": "010570000000", + "Giekau (Plön - Schleswig-Holstein)": "010570000000", + "Helmstorf (Plön - Schleswig-Holstein)": "010570000000", + "Högsdorf (Plön - Schleswig-Holstein)": "010570000000", + "Hohenfelde (Plön - Schleswig-Holstein)": "010570000000", + "Hohwacht (Ostsee) (Plön - Schleswig-Holstein)": "010570000000", + "Kirchnüchel (Plön - Schleswig-Holstein)": "010570000000", + "Klamp (Plön - Schleswig-Holstein)": "010570000000", + "Kletkamp (Plön - Schleswig-Holstein)": "010570000000", + "Lütjenburg, Stadt (Plön - Schleswig-Holstein)": "010570000000", + "Panker (Plön - Schleswig-Holstein)": "010570000000", + "Schwartbuck (Plön - Schleswig-Holstein)": "010570000000", + "Tröndel (Plön - Schleswig-Holstein)": "010570000000", + "Dersau (Plön - Schleswig-Holstein)": "010570000000", + "Dörnick (Plön - Schleswig-Holstein)": "010570000000", + "Grebin (Plön - Schleswig-Holstein)": "010570000000", + "Kalübbe (Plön - Schleswig-Holstein)": "010570000000", + "Lebrade (Plön - Schleswig-Holstein)": "010570000000", + "Nehmten (Plön - Schleswig-Holstein)": "010570000000", + "Rantzau (Plön - Schleswig-Holstein)": "010570000000", + "Rathjensdorf (Plön - Schleswig-Holstein)": "010570000000", + "Wittmoldt (Plön - Schleswig-Holstein)": "010570000000", + "Barmissen (Plön - Schleswig-Holstein)": "010570000000", + "Boksee (Plön - Schleswig-Holstein)": "010570000000", + "Bothkamp (Plön - Schleswig-Holstein)": "010570000000", + "Großbarkau (Plön - Schleswig-Holstein)": "010570000000", + "Honigsee (Plön - Schleswig-Holstein)": "010570000000", + "Kirchbarkau (Plön - Schleswig-Holstein)": "010570000000", + "Klein Barkau (Plön - Schleswig-Holstein)": "010570000000", + "Kühren (Plön - Schleswig-Holstein)": "010570000000", + "Lehmkuhlen (Plön - Schleswig-Holstein)": "010570000000", + "Löptin (Plön - Schleswig-Holstein)": "010570000000", + "Nettelsee (Plön - Schleswig-Holstein)": "010570000000", + "Pohnsdorf (Plön - Schleswig-Holstein)": "010570000000", + "Postfeld (Plön - Schleswig-Holstein)": "010570000000", + "Rastorf (Plön - Schleswig-Holstein)": "010570000000", + "Schellhorn (Plön - Schleswig-Holstein)": "010570000000", + "Wahlstorf (Plön - Schleswig-Holstein)": "010570000000", + "Warnau (Plön - Schleswig-Holstein)": "010570000000", + "Barsbek (Plön - Schleswig-Holstein)": "010570000000", + "Bendfeld (Plön - Schleswig-Holstein)": "010570000000", + "Brodersdorf (Plön - Schleswig-Holstein)": "010570000000", + "Fahren (Plön - Schleswig-Holstein)": "010570000000", + "Fiefbergen (Plön - Schleswig-Holstein)": "010570000000", + "Höhndorf (Plön - Schleswig-Holstein)": "010570000000", + "Köhn (Plön - Schleswig-Holstein)": "010570000000", + "Krokau (Plön - Schleswig-Holstein)": "010570000000", + "Krummbek (Plön - Schleswig-Holstein)": "010570000000", + "Laboe (Plön - Schleswig-Holstein)": "010570000000", + "Lutterbek (Plön - Schleswig-Holstein)": "010570000000", + "Passade (Plön - Schleswig-Holstein)": "010570000000", + "Prasdorf (Plön - Schleswig-Holstein)": "010570000000", + "Probsteierhagen (Plön - Schleswig-Holstein)": "010570000000", + "Schönberg (Holstein) (Plön - Schleswig-Holstein)": "010570000000", + "Stakendorf (Plön - Schleswig-Holstein)": "010570000000", + "Stein (Plön - Schleswig-Holstein)": "010570000000", + "Stoltenberg (Plön - Schleswig-Holstein)": "010570000000", + "Wendtorf (Plön - Schleswig-Holstein)": "010570000000", + "Wisch (Plön - Schleswig-Holstein)": "010570000000", + "Dobersdorf (Plön - Schleswig-Holstein)": "010570000000", + "Lammershagen (Plön - Schleswig-Holstein)": "010570000000", + "Martensrade (Plön - Schleswig-Holstein)": "010570000000", + "Mucheln (Plön - Schleswig-Holstein)": "010570000000", + "Schlesen (Plön - Schleswig-Holstein)": "010570000000", + "Selent (Plön - Schleswig-Holstein)": "010570000000", + "Fargau-Pratjau (Plön - Schleswig-Holstein)": "010570000000", + "Heikendorf (Plön - Schleswig-Holstein)": "010570000000", + "Mönkeberg (Plön - Schleswig-Holstein)": "010570000000", + "Schönkirchen (Plön - Schleswig-Holstein)": "010570000000", + "Belau (Plön - Schleswig-Holstein)": "010570000000", + "Großharrie (Plön - Schleswig-Holstein)": "010570000000", + "Rendswühren (Plön - Schleswig-Holstein)": "010570000000", + "Ruhwinkel (Plön - Schleswig-Holstein)": "010570000000", + "Schillsdorf (Plön - Schleswig-Holstein)": "010570000000", + "Stolpe (Plön - Schleswig-Holstein)": "010570000000", + "Tasdorf (Plön - Schleswig-Holstein)": "010570000000", + "Wankendorf (Plön - Schleswig-Holstein)": "010570000000", + "Altenholz (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Büdelsdorf, Stadt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Eckernförde, Stadt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Kronshagen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rendsburg, Stadt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Wasbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Achterwehr (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bredenbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Felde (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Krummwisch (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Melsdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Ottendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Quarnbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Westensee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Dänischenhagen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Noer (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schwedeneck (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Strande (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Felm (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Gettorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Lindau (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Neudorf-Bornstein (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Neuwittenbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Osdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schinkel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Tüttendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Böhnhusen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Flintbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schönhorst (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Techelsdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Alt Duvenstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Fockbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Nübbel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rickert (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bargstall (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Breiholz (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Christiansholm (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Elsdorf-Westermühlen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Friedrichsgraben (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Friedrichsholm (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hamdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hohn (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Königshügel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Lohe-Föhrden (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Prinzenmoor (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Sophienhamm (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Brinjahe (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Embühren (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Haale (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hamweddel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hörsten (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Jevenstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Luhnstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schülp b. Rendsburg (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Stafstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Westerrönfeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Blumenthal (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Mielkendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Molfsee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rodenbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rumohr (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schierensee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bargstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bokel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Borgdorf-Seedorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Brammer (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Dätgen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Eisendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Ellerdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Emkendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Gnutz (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Groß Vollstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Krogaspe (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Langwedel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Nortorf, Stadt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Oldenhütten (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schülp b. Nortorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Timmaspe (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Warder (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bovenau (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Haßmoor (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Ostenfeld (Rendsburg) (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Osterrönfeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rade b. Rendsburg (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schacht-Audorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schülldorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bissee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bordesholm (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Brügge (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Grevenkrug (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Groß Buchwald (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hoffeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Loop (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Mühbrook (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Negenharrie (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Reesdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schmalstede (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Schönbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Sören (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Wattenbek (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Ascheffel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Borgstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Brekendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bünsdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Damendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Groß Wittensee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Haby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Holtsee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Holzbunge (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hütten (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Klein Wittensee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Neu Duvenstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Osterby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Owschlag (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Sehestedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Ahlefeld-Bistensee (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Altenhof (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Barkelsby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Brodersby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Damp (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Dörphof (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Fleckeby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Gammelby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Güby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Holzdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hummelfeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Karby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Kosel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Loose (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Goosefeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rieseby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Thumby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Waabs (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Windeby (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Winnemark (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Arpsdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Aukrug (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Beldorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Beringstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Bornholt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Ehndorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Gokels (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Grauel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hanerau-Hademarschen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Heinkenborstel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Hohenwestedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Jahrsdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Lütjenwestedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Meezen (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Mörel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Nienborstel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Nindorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Oldenbüttel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Osterstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Padenstedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Rade b. Hohenwestedt (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Remmels (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Seefeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Steenfeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Tackesdorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Tappendorf (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Thaden (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Todenbüttel (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Wapelfeld (Rendsburg-Eckernförde - Schleswig-Holstein)": "010580000000", + "Kappeln, Stadt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Schleswig, Stadt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Glücksburg (Ostsee), Stadt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Harrislee (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Handewitt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Eggebek (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Janneby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Jerrishoe (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Jörl (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Langstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Sollerup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Süderhackstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Wanderup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Borgwedel (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Busdorf (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Dannewerk (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Fahrdorf (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Geltorf (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Jagel (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Lottorf (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Selk (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Tastrup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Ausacker (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Großsolt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Hürup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Husby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Maasbüll (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Freienwill (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Arnis, Stadt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Grödersby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Oersberg (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Rabenkirchen-Faulück (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Dollerup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Grundhof (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Langballig (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Munkbrarup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Ringsberg (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Wees (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Westerholz (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Sieverstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Tarp (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Oeversee (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Schnarup-Thumby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Sörup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Mittelangeln (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Böxlund (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Großenwiehe (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Hörup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Holt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Jardelund (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Medelby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Meyn (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Nordhackstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Osterby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Schafflund (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Wallsbüll (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Weesby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Lindewitt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Böel (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Loit (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Mohrkirch (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Norderbrarup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Nottfeld (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Rügge (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Saustrup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Scheggerott (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Steinfeld (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Süderbrarup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Ulsnis (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Wagersrott (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Boren (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Böklund (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Havetoft (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Idstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Klappholz (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Neuberend (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Schaalby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Stolk (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Struxdorf (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Süderfahrenstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Taarstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Tolk (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Uelsby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Twedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Nübel (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Brodersby-Goltoft (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Ahneby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Esgrus (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Gelting (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Hasselberg (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Kronsgaard (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Maasholm (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Nieby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Niesgrau (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Pommerby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Rabel (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Rabenholz (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Stangheck (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Steinberg (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Sterup (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Stoltebüll (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Steinbergkirche (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Bollingstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Ellingstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Hollingstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Hüsby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Jübek (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Lürschau (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Schuby (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Silberstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Treia (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Alt Bennebek (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Bergenhusen (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Börm (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Dörpstedt (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Erfde (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Groß Rheide (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Klein Bennebek (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Klein Rheide (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Kropp (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Meggerdorf (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Tetenhusen (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Tielen (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Wohlde (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Stapel (Schleswig-Flensburg - Schleswig-Holstein)": "010590000000", + "Bad Bramstedt, Stadt (Segeberg - Schleswig-Holstein)": "010600000000", + "Bad Segeberg, Stadt (Segeberg - Schleswig-Holstein)": "010600000000", + "Ellerau (Segeberg - Schleswig-Holstein)": "010600000000", + "Henstedt-Ulzburg (Segeberg - Schleswig-Holstein)": "010600000000", + "Kaltenkirchen, Stadt (Segeberg - Schleswig-Holstein)": "010600000000", + "Norderstedt, Stadt (Segeberg - Schleswig-Holstein)": "010600000000", + "Wahlstedt, Stadt (Segeberg - Schleswig-Holstein)": "010600000000", + "Armstedt (Segeberg - Schleswig-Holstein)": "010600000000", + "Bimöhlen (Segeberg - Schleswig-Holstein)": "010600000000", + "Borstel (Segeberg - Schleswig-Holstein)": "010600000000", + "Föhrden-Barl (Segeberg - Schleswig-Holstein)": "010600000000", + "Fuhlendorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Großenaspe (Segeberg - Schleswig-Holstein)": "010600000000", + "Hagen (Segeberg - Schleswig-Holstein)": "010600000000", + "Hardebek (Segeberg - Schleswig-Holstein)": "010600000000", + "Hasenkrug (Segeberg - Schleswig-Holstein)": "010600000000", + "Heidmoor (Segeberg - Schleswig-Holstein)": "010600000000", + "Hitzhusen (Segeberg - Schleswig-Holstein)": "010600000000", + "Mönkloh (Segeberg - Schleswig-Holstein)": "010600000000", + "Weddelbrook (Segeberg - Schleswig-Holstein)": "010600000000", + "Wiemersdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Bornhöved (Segeberg - Schleswig-Holstein)": "010600000000", + "Damsdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Gönnebek (Segeberg - Schleswig-Holstein)": "010600000000", + "Schmalensee (Segeberg - Schleswig-Holstein)": "010600000000", + "Stocksee (Segeberg - Schleswig-Holstein)": "010600000000", + "Tarbek (Segeberg - Schleswig-Holstein)": "010600000000", + "Tensfeld (Segeberg - Schleswig-Holstein)": "010600000000", + "Trappenkamp (Segeberg - Schleswig-Holstein)": "010600000000", + "Itzstedt (Segeberg - Schleswig-Holstein)": "010600000000", + "Kayhude (Segeberg - Schleswig-Holstein)": "010600000000", + "Nahe (Segeberg - Schleswig-Holstein)": "010600000000", + "Oering (Segeberg - Schleswig-Holstein)": "010600000000", + "Seth (Segeberg - Schleswig-Holstein)": "010600000000", + "Sülfeld (Segeberg - Schleswig-Holstein)": "010600000000", + "Alveslohe (Segeberg - Schleswig-Holstein)": "010600000000", + "Hartenholm (Segeberg - Schleswig-Holstein)": "010600000000", + "Hasenmoor (Segeberg - Schleswig-Holstein)": "010600000000", + "Lentföhrden (Segeberg - Schleswig-Holstein)": "010600000000", + "Nützen (Segeberg - Schleswig-Holstein)": "010600000000", + "Schmalfeld (Segeberg - Schleswig-Holstein)": "010600000000", + "Hüttblek (Segeberg - Schleswig-Holstein)": "010600000000", + "Kattendorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Kisdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Oersdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Sievershütten (Segeberg - Schleswig-Holstein)": "010600000000", + "Struvenhütten (Segeberg - Schleswig-Holstein)": "010600000000", + "Stuvenborn (Segeberg - Schleswig-Holstein)": "010600000000", + "Wakendorf II (Segeberg - Schleswig-Holstein)": "010600000000", + "Winsen (Segeberg - Schleswig-Holstein)": "010600000000", + "Bark (Segeberg - Schleswig-Holstein)": "010600000000", + "Bebensee (Segeberg - Schleswig-Holstein)": "010600000000", + "Fredesdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Groß Niendorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Högersdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Kükels (Segeberg - Schleswig-Holstein)": "010600000000", + "Leezen (Segeberg - Schleswig-Holstein)": "010600000000", + "Mözen (Segeberg - Schleswig-Holstein)": "010600000000", + "Neversdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Schwissel (Segeberg - Schleswig-Holstein)": "010600000000", + "Todesfelde (Segeberg - Schleswig-Holstein)": "010600000000", + "Wittenborn (Segeberg - Schleswig-Holstein)": "010600000000", + "Boostedt (Segeberg - Schleswig-Holstein)": "010600000000", + "Daldorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Groß Kummerfeld (Segeberg - Schleswig-Holstein)": "010600000000", + "Heidmühlen (Segeberg - Schleswig-Holstein)": "010600000000", + "Latendorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Rickling (Segeberg - Schleswig-Holstein)": "010600000000", + "Bahrenhof (Segeberg - Schleswig-Holstein)": "010600000000", + "Blunk (Segeberg - Schleswig-Holstein)": "010600000000", + "Bühnsdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Dreggers (Segeberg - Schleswig-Holstein)": "010600000000", + "Fahrenkrug (Segeberg - Schleswig-Holstein)": "010600000000", + "Geschendorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Glasau (Segeberg - Schleswig-Holstein)": "010600000000", + "Groß Rönnau (Segeberg - Schleswig-Holstein)": "010600000000", + "Klein Gladebrügge (Segeberg - Schleswig-Holstein)": "010600000000", + "Klein Rönnau (Segeberg - Schleswig-Holstein)": "010600000000", + "Krems II (Segeberg - Schleswig-Holstein)": "010600000000", + "Negernbötel (Segeberg - Schleswig-Holstein)": "010600000000", + "Nehms (Segeberg - Schleswig-Holstein)": "010600000000", + "Neuengörs (Segeberg - Schleswig-Holstein)": "010600000000", + "Pronstorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Rohlstorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Schackendorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Schieren (Segeberg - Schleswig-Holstein)": "010600000000", + "Seedorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Stipsdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Strukdorf (Segeberg - Schleswig-Holstein)": "010600000000", + "Travenhorst (Segeberg - Schleswig-Holstein)": "010600000000", + "Traventhal (Segeberg - Schleswig-Holstein)": "010600000000", + "Wakendorf I (Segeberg - Schleswig-Holstein)": "010600000000", + "Weede (Segeberg - Schleswig-Holstein)": "010600000000", + "Wensin (Segeberg - Schleswig-Holstein)": "010600000000", + "Westerrade (Segeberg - Schleswig-Holstein)": "010600000000", + "Buchholz (Forstgutsbez.),gemfr. Gebiet (Segeberg - Schleswig-Holstein)": "010600000000", + "Glückstadt, Stadt (Steinburg - Schleswig-Holstein)": "010610000000", + "Itzehoe, Stadt (Steinburg - Schleswig-Holstein)": "010610000000", + "Wilster, Stadt (Steinburg - Schleswig-Holstein)": "010610000000", + "Auufer (Steinburg - Schleswig-Holstein)": "010610000000", + "Breitenberg (Steinburg - Schleswig-Holstein)": "010610000000", + "Breitenburg (Steinburg - Schleswig-Holstein)": "010610000000", + "Kollmoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Kronsmoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Lägerdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Moordiek (Steinburg - Schleswig-Holstein)": "010610000000", + "Münsterdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Oelixdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Westermoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Wittenbergen (Steinburg - Schleswig-Holstein)": "010610000000", + "Altenmoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Blomesche Wildnis (Steinburg - Schleswig-Holstein)": "010610000000", + "Borsfleth (Steinburg - Schleswig-Holstein)": "010610000000", + "Engelbrechtsche Wildnis (Steinburg - Schleswig-Holstein)": "010610000000", + "Herzhorn (Steinburg - Schleswig-Holstein)": "010610000000", + "Hohenfelde (Steinburg - Schleswig-Holstein)": "010610000000", + "Horst (Holstein) (Steinburg - Schleswig-Holstein)": "010610000000", + "Kiebitzreihe (Steinburg - Schleswig-Holstein)": "010610000000", + "Krempdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Neuendorf b. Elmshorn (Steinburg - Schleswig-Holstein)": "010610000000", + "Sommerland (Steinburg - Schleswig-Holstein)": "010610000000", + "Kollmar (Steinburg - Schleswig-Holstein)": "010610000000", + "Bekdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Bekmünde (Steinburg - Schleswig-Holstein)": "010610000000", + "Drage (Steinburg - Schleswig-Holstein)": "010610000000", + "Heiligenstedten (Steinburg - Schleswig-Holstein)": "010610000000", + "Heiligenstedtenerkamp (Steinburg - Schleswig-Holstein)": "010610000000", + "Hodorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Hohenaspe (Steinburg - Schleswig-Holstein)": "010610000000", + "Huje (Steinburg - Schleswig-Holstein)": "010610000000", + "Kaaks (Steinburg - Schleswig-Holstein)": "010610000000", + "Kleve (Steinburg - Schleswig-Holstein)": "010610000000", + "Krummendiek (Steinburg - Schleswig-Holstein)": "010610000000", + "Lohbarbek (Steinburg - Schleswig-Holstein)": "010610000000", + "Mehlbek (Steinburg - Schleswig-Holstein)": "010610000000", + "Moorhusen (Steinburg - Schleswig-Holstein)": "010610000000", + "Oldendorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Ottenbüttel (Steinburg - Schleswig-Holstein)": "010610000000", + "Peissen (Steinburg - Schleswig-Holstein)": "010610000000", + "Schlotfeld (Steinburg - Schleswig-Holstein)": "010610000000", + "Silzen (Steinburg - Schleswig-Holstein)": "010610000000", + "Winseldorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Bahrenfleth (Steinburg - Schleswig-Holstein)": "010610000000", + "Dägeling (Steinburg - Schleswig-Holstein)": "010610000000", + "Elskop (Steinburg - Schleswig-Holstein)": "010610000000", + "Grevenkop (Steinburg - Schleswig-Holstein)": "010610000000", + "Krempe, Stadt (Steinburg - Schleswig-Holstein)": "010610000000", + "Kremperheide (Steinburg - Schleswig-Holstein)": "010610000000", + "Krempermoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Neuenbrook (Steinburg - Schleswig-Holstein)": "010610000000", + "Rethwisch (Steinburg - Schleswig-Holstein)": "010610000000", + "Süderau (Steinburg - Schleswig-Holstein)": "010610000000", + "Aasbüttel (Steinburg - Schleswig-Holstein)": "010610000000", + "Agethorst (Steinburg - Schleswig-Holstein)": "010610000000", + "Besdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Bokelrehm (Steinburg - Schleswig-Holstein)": "010610000000", + "Bokhorst (Steinburg - Schleswig-Holstein)": "010610000000", + "Christinenthal (Steinburg - Schleswig-Holstein)": "010610000000", + "Gribbohm (Steinburg - Schleswig-Holstein)": "010610000000", + "Hadenfeld (Steinburg - Schleswig-Holstein)": "010610000000", + "Holstenniendorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Kaisborstel (Steinburg - Schleswig-Holstein)": "010610000000", + "Looft (Steinburg - Schleswig-Holstein)": "010610000000", + "Nienbüttel (Steinburg - Schleswig-Holstein)": "010610000000", + "Nutteln (Steinburg - Schleswig-Holstein)": "010610000000", + "Oldenborstel (Steinburg - Schleswig-Holstein)": "010610000000", + "Pöschendorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Puls (Steinburg - Schleswig-Holstein)": "010610000000", + "Reher (Steinburg - Schleswig-Holstein)": "010610000000", + "Schenefeld (Steinburg - Schleswig-Holstein)": "010610000000", + "Vaale (Steinburg - Schleswig-Holstein)": "010610000000", + "Vaalermoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Wacken (Steinburg - Schleswig-Holstein)": "010610000000", + "Warringholz (Steinburg - Schleswig-Holstein)": "010610000000", + "Aebtissinwisch (Steinburg - Schleswig-Holstein)": "010610000000", + "Beidenfleth (Steinburg - Schleswig-Holstein)": "010610000000", + "Brokdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Büttel (Steinburg - Schleswig-Holstein)": "010610000000", + "Dammfleth (Steinburg - Schleswig-Holstein)": "010610000000", + "Ecklak (Steinburg - Schleswig-Holstein)": "010610000000", + "Kudensee (Steinburg - Schleswig-Holstein)": "010610000000", + "Landrecht (Steinburg - Schleswig-Holstein)": "010610000000", + "Landscheide (Steinburg - Schleswig-Holstein)": "010610000000", + "Nortorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Sankt Margarethen (Steinburg - Schleswig-Holstein)": "010610000000", + "Stördorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Wewelsfleth (Steinburg - Schleswig-Holstein)": "010610000000", + "Neuendorf-Sachsenbande (Steinburg - Schleswig-Holstein)": "010610000000", + "Brokstedt (Steinburg - Schleswig-Holstein)": "010610000000", + "Fitzbek (Steinburg - Schleswig-Holstein)": "010610000000", + "Hennstedt (Steinburg - Schleswig-Holstein)": "010610000000", + "Hingstheide (Steinburg - Schleswig-Holstein)": "010610000000", + "Hohenlockstedt (Steinburg - Schleswig-Holstein)": "010610000000", + "Kellinghusen, Stadt (Steinburg - Schleswig-Holstein)": "010610000000", + "Lockstedt (Steinburg - Schleswig-Holstein)": "010610000000", + "Mühlenbarbek (Steinburg - Schleswig-Holstein)": "010610000000", + "Oeschebüttel (Steinburg - Schleswig-Holstein)": "010610000000", + "Poyenberg (Steinburg - Schleswig-Holstein)": "010610000000", + "Quarnstedt (Steinburg - Schleswig-Holstein)": "010610000000", + "Rade (Steinburg - Schleswig-Holstein)": "010610000000", + "Rosdorf (Steinburg - Schleswig-Holstein)": "010610000000", + "Sarlhusen (Steinburg - Schleswig-Holstein)": "010610000000", + "Störkathen (Steinburg - Schleswig-Holstein)": "010610000000", + "Wiedenborstel (Steinburg - Schleswig-Holstein)": "010610000000", + "Willenscharen (Steinburg - Schleswig-Holstein)": "010610000000", + "Wrist (Steinburg - Schleswig-Holstein)": "010610000000", + "Wulfsmoor (Steinburg - Schleswig-Holstein)": "010610000000", + "Ahrensburg, Stadt (Stormarn - Schleswig-Holstein)": "010620000000", + "Bad Oldesloe, Stadt (Stormarn - Schleswig-Holstein)": "010620000000", + "Bargteheide, Stadt (Stormarn - Schleswig-Holstein)": "010620000000", + "Barsbüttel (Stormarn - Schleswig-Holstein)": "010620000000", + "Glinde, Stadt (Stormarn - Schleswig-Holstein)": "010620000000", + "Großhansdorf (Stormarn - Schleswig-Holstein)": "010620000000", + "Oststeinbek (Stormarn - Schleswig-Holstein)": "010620000000", + "Reinbek, Stadt (Stormarn - Schleswig-Holstein)": "010620000000", + "Reinfeld (Holstein), Stadt (Stormarn - Schleswig-Holstein)": "010620000000", + "Tangstedt (Stormarn - Schleswig-Holstein)": "010620000000", + "Ammersbek (Stormarn - Schleswig-Holstein)": "010620000000", + "Grabau (Stormarn - Schleswig-Holstein)": "010620000000", + "Meddewade (Stormarn - Schleswig-Holstein)": "010620000000", + "Neritz (Stormarn - Schleswig-Holstein)": "010620000000", + "Pölitz (Stormarn - Schleswig-Holstein)": "010620000000", + "Rethwisch (Stormarn - Schleswig-Holstein)": "010620000000", + "Rümpel (Stormarn - Schleswig-Holstein)": "010620000000", + "Lasbek (Stormarn - Schleswig-Holstein)": "010620000000", + "Steinburg (Stormarn - Schleswig-Holstein)": "010620000000", + "Travenbrück (Stormarn - Schleswig-Holstein)": "010620000000", + "Bargfeld-Stegen (Stormarn - Schleswig-Holstein)": "010620000000", + "Delingsdorf (Stormarn - Schleswig-Holstein)": "010620000000", + "Elmenhorst (Stormarn - Schleswig-Holstein)": "010620000000", + "Hammoor (Stormarn - Schleswig-Holstein)": "010620000000", + "Jersbek (Stormarn - Schleswig-Holstein)": "010620000000", + "Nienwohld (Stormarn - Schleswig-Holstein)": "010620000000", + "Todendorf (Stormarn - Schleswig-Holstein)": "010620000000", + "Tremsbüttel (Stormarn - Schleswig-Holstein)": "010620000000", + "Badendorf (Stormarn - Schleswig-Holstein)": "010620000000", + "Barnitz (Stormarn - Schleswig-Holstein)": "010620000000", + "Hamberge (Stormarn - Schleswig-Holstein)": "010620000000", + "Heidekamp (Stormarn - Schleswig-Holstein)": "010620000000", + "Heilshoop (Stormarn - Schleswig-Holstein)": "010620000000", + "Klein Wesenberg (Stormarn - Schleswig-Holstein)": "010620000000", + "Mönkhagen (Stormarn - Schleswig-Holstein)": "010620000000", + "Rehhorst (Stormarn - Schleswig-Holstein)": "010620000000", + "Westerau (Stormarn - Schleswig-Holstein)": "010620000000", + "Zarpen (Stormarn - Schleswig-Holstein)": "010620000000", + "Feldhorst (Stormarn - Schleswig-Holstein)": "010620000000", + "Wesenberg (Stormarn - Schleswig-Holstein)": "010620000000", + "Braak (Stormarn - Schleswig-Holstein)": "010620000000", + "Hoisdorf (Stormarn - Schleswig-Holstein)": "010620000000", + "Siek (Stormarn - Schleswig-Holstein)": "010620000000", + "Stapelfeld (Stormarn - Schleswig-Holstein)": "010620000000", + "Brunsbek (Stormarn - Schleswig-Holstein)": "010620000000", + "Grande (Stormarn - Schleswig-Holstein)": "010620000000", + "Grönwohld (Stormarn - Schleswig-Holstein)": "010620000000", + "Großensee (Stormarn - Schleswig-Holstein)": "010620000000", + "Hamfelde (Stormarn - Schleswig-Holstein)": "010620000000", + "Hohenfelde (Stormarn - Schleswig-Holstein)": "010620000000", + "Köthel (Stormarn - Schleswig-Holstein)": "010620000000", + "Lütjensee (Stormarn - Schleswig-Holstein)": "010620000000", + "Rausdorf (Stormarn - Schleswig-Holstein)": "010620000000", + "Trittau (Stormarn - Schleswig-Holstein)": "010620000000", + "Witzhave (Stormarn - Schleswig-Holstein)": "010620000000", + "Hamburg, Freie und Hansestadt": "020000000000", + "Braunschweig, Stadt": "031010000000", + "Salzgitter, Stadt": "031020000000", + "Wolfsburg, Stadt": "031030000000", + "Gifhorn, Stadt (Gifhorn - Niedersachsen)": "031510000000", + "Sassenburg (Gifhorn - Niedersachsen)": "031510000000", + "Wittingen, Stadt (Gifhorn - Niedersachsen)": "031510000000", + "Barwedel (Gifhorn - Niedersachsen)": "031510000000", + "Bokensdorf (Gifhorn - Niedersachsen)": "031510000000", + "Jembke (Gifhorn - Niedersachsen)": "031510000000", + "Osloß (Gifhorn - Niedersachsen)": "031510000000", + "Tappenbeck (Gifhorn - Niedersachsen)": "031510000000", + "Weyhausen (Gifhorn - Niedersachsen)": "031510000000", + "Bergfeld (Gifhorn - Niedersachsen)": "031510000000", + "Brome, Flecken (Gifhorn - Niedersachsen)": "031510000000", + "Ehra-Lessien (Gifhorn - Niedersachsen)": "031510000000", + "Parsau (Gifhorn - Niedersachsen)": "031510000000", + "Rühen (Gifhorn - Niedersachsen)": "031510000000", + "Tiddische (Gifhorn - Niedersachsen)": "031510000000", + "Tülau (Gifhorn - Niedersachsen)": "031510000000", + "Dedelstorf (Gifhorn - Niedersachsen)": "031510000000", + "Hankensbüttel (Gifhorn - Niedersachsen)": "031510000000", + "Obernholz (Gifhorn - Niedersachsen)": "031510000000", + "Sprakensehl (Gifhorn - Niedersachsen)": "031510000000", + "Steinhorst (Gifhorn - Niedersachsen)": "031510000000", + "Calberlah (Gifhorn - Niedersachsen)": "031510000000", + "Isenbüttel (Gifhorn - Niedersachsen)": "031510000000", + "Ribbesbüttel (Gifhorn - Niedersachsen)": "031510000000", + "Wasbüttel (Gifhorn - Niedersachsen)": "031510000000", + "Hillerse (Gifhorn - Niedersachsen)": "031510000000", + "Leiferde (Gifhorn - Niedersachsen)": "031510000000", + "Meinersen (Gifhorn - Niedersachsen)": "031510000000", + "Müden (Aller) (Gifhorn - Niedersachsen)": "031510000000", + "Adenbüttel (Gifhorn - Niedersachsen)": "031510000000", + "Meine (Gifhorn - Niedersachsen)": "031510000000", + "Rötgesbüttel (Gifhorn - Niedersachsen)": "031510000000", + "Schwülper (Gifhorn - Niedersachsen)": "031510000000", + "Vordorf (Gifhorn - Niedersachsen)": "031510000000", + "Didderse (Gifhorn - Niedersachsen)": "031510000000", + "Groß Oesingen (Gifhorn - Niedersachsen)": "031510000000", + "Schönewörde (Gifhorn - Niedersachsen)": "031510000000", + "Ummern (Gifhorn - Niedersachsen)": "031510000000", + "Wagenhoff (Gifhorn - Niedersachsen)": "031510000000", + "Wahrenholz (Gifhorn - Niedersachsen)": "031510000000", + "Wesendorf (Gifhorn - Niedersachsen)": "031510000000", + "Giebel, gemfr. Gebiet (Gifhorn - Niedersachsen)": "031510000000", + "Bad Harzburg, Stadt (Goslar - Niedersachsen)": "031530000000", + "Langelsheim, Stadt (Goslar - Niedersachsen)": "031530000000", + "Liebenburg (Goslar - Niedersachsen)": "031530000000", + "Seesen, Stadt (Goslar - Niedersachsen)": "031530000000", + "Braunlage, Stadt (Goslar - Niedersachsen)": "031530000000", + "Goslar, Stadt (Goslar - Niedersachsen)": "031530000000", + "Clausthal-Zellerfeld, Berg- und Universitätsstadt (Goslar - Niedersachsen)": "031530000000", + "Hahausen (Goslar - Niedersachsen)": "031530000000", + "Lutter am Barenberge, Flecken (Goslar - Niedersachsen)": "031530000000", + "Wallmoden (Goslar - Niedersachsen)": "031530000000", + "Harz (Landkreis Goslar), gemfr. Gebiet (Goslar - Niedersachsen)": "031530000000", + "Königslutter am Elm, Stadt (Helmstedt - Niedersachsen)": "031540000000", + "Lehre (Helmstedt - Niedersachsen)": "031540000000", + "Schöningen, Stadt (Helmstedt - Niedersachsen)": "031540000000", + "Helmstedt, Stadt (Helmstedt - Niedersachsen)": "031540000000", + "Grasleben (Helmstedt - Niedersachsen)": "031540000000", + "Mariental (Helmstedt - Niedersachsen)": "031540000000", + "Querenhorst (Helmstedt - Niedersachsen)": "031540000000", + "Rennau (Helmstedt - Niedersachsen)": "031540000000", + "Beierstedt (Helmstedt - Niedersachsen)": "031540000000", + "Gevensleben (Helmstedt - Niedersachsen)": "031540000000", + "Jerxheim (Helmstedt - Niedersachsen)": "031540000000", + "Söllingen (Helmstedt - Niedersachsen)": "031540000000", + "Frellstedt (Helmstedt - Niedersachsen)": "031540000000", + "Räbke (Helmstedt - Niedersachsen)": "031540000000", + "Süpplingen (Helmstedt - Niedersachsen)": "031540000000", + "Süpplingenburg (Helmstedt - Niedersachsen)": "031540000000", + "Warberg (Helmstedt - Niedersachsen)": "031540000000", + "Wolsdorf (Helmstedt - Niedersachsen)": "031540000000", + "Bahrdorf (Helmstedt - Niedersachsen)": "031540000000", + "Danndorf (Helmstedt - Niedersachsen)": "031540000000", + "Grafhorst (Helmstedt - Niedersachsen)": "031540000000", + "Groß Twülpstedt (Helmstedt - Niedersachsen)": "031540000000", + "Velpke (Helmstedt - Niedersachsen)": "031540000000", + "Brunsleberfeld, gemfr. Gebiet (Helmstedt - Niedersachsen)": "031540000000", + "Helmstedt, gemfr. Gebiet (Helmstedt - Niedersachsen)": "031540000000", + "Königslutter, gemfr. Gebiet (Helmstedt - Niedersachsen)": "031540000000", + "Mariental, gemfr. Gebiet (Helmstedt - Niedersachsen)": "031540000000", + "Schöningen, gemfr. Gebiet (Helmstedt - Niedersachsen)": "031540000000", + "Bad Gandersheim, Stadt (Northeim - Niedersachsen)": "031550000000", + "Bodenfelde, Flecken (Northeim - Niedersachsen)": "031550000000", + "Dassel, Stadt (Northeim - Niedersachsen)": "031550000000", + "Hardegsen, Stadt (Northeim - Niedersachsen)": "031550000000", + "Kalefeld (Northeim - Niedersachsen)": "031550000000", + "Katlenburg-Lindau (Northeim - Niedersachsen)": "031550000000", + "Moringen, Stadt (Northeim - Niedersachsen)": "031550000000", + "Nörten-Hardenberg, Flecken (Northeim - Niedersachsen)": "031550000000", + "Northeim, Stadt (Northeim - Niedersachsen)": "031550000000", + "Uslar, Stadt (Northeim - Niedersachsen)": "031550000000", + "Einbeck, Stadt (Northeim - Niedersachsen)": "031550000000", + "Solling (Landkreis Northeim), gemfr. Geb. (Northeim - Niedersachsen)": "031550000000", + "Edemissen (Peine - Niedersachsen)": "031570000000", + "Hohenhameln (Peine - Niedersachsen)": "031570000000", + "Lengede (Peine - Niedersachsen)": "031570000000", + "Peine, Stadt (Peine - Niedersachsen)": "031570000000", + "Vechelde (Peine - Niedersachsen)": "031570000000", + "Wendeburg (Peine - Niedersachsen)": "031570000000", + "Ilsede (Peine - Niedersachsen)": "031570000000", + "Cremlingen (Wolfenbüttel - Niedersachsen)": "031580000000", + "Wolfenbüttel, Stadt (Wolfenbüttel - Niedersachsen)": "031580000000", + "Schladen-Werla (Wolfenbüttel - Niedersachsen)": "031580000000", + "Baddeckenstedt (Wolfenbüttel - Niedersachsen)": "031580000000", + "Burgdorf (Wolfenbüttel - Niedersachsen)": "031580000000", + "Elbe (Wolfenbüttel - Niedersachsen)": "031580000000", + "Haverlah (Wolfenbüttel - Niedersachsen)": "031580000000", + "Heere (Wolfenbüttel - Niedersachsen)": "031580000000", + "Sehlde (Wolfenbüttel - Niedersachsen)": "031580000000", + "Cramme (Wolfenbüttel - Niedersachsen)": "031580000000", + "Dorstadt (Wolfenbüttel - Niedersachsen)": "031580000000", + "Flöthe (Wolfenbüttel - Niedersachsen)": "031580000000", + "Heiningen (Wolfenbüttel - Niedersachsen)": "031580000000", + "Ohrum (Wolfenbüttel - Niedersachsen)": "031580000000", + "Börßum (Wolfenbüttel - Niedersachsen)": "031580000000", + "Dettum (Wolfenbüttel - Niedersachsen)": "031580000000", + "Erkerode (Wolfenbüttel - Niedersachsen)": "031580000000", + "Evessen (Wolfenbüttel - Niedersachsen)": "031580000000", + "Sickte (Wolfenbüttel - Niedersachsen)": "031580000000", + "Veltheim (Ohe) (Wolfenbüttel - Niedersachsen)": "031580000000", + "Dahlum (Wolfenbüttel - Niedersachsen)": "031580000000", + "Denkte (Wolfenbüttel - Niedersachsen)": "031580000000", + "Hedeper (Wolfenbüttel - Niedersachsen)": "031580000000", + "Kissenbrück (Wolfenbüttel - Niedersachsen)": "031580000000", + "Kneitlingen (Wolfenbüttel - Niedersachsen)": "031580000000", + "Roklum (Wolfenbüttel - Niedersachsen)": "031580000000", + "Schöppenstedt, Stadt (Wolfenbüttel - Niedersachsen)": "031580000000", + "Uehrde (Wolfenbüttel - Niedersachsen)": "031580000000", + "Vahlberg (Wolfenbüttel - Niedersachsen)": "031580000000", + "Winnigstedt (Wolfenbüttel - Niedersachsen)": "031580000000", + "Wittmar (Wolfenbüttel - Niedersachsen)": "031580000000", + "Remlingen-Semmenstedt (Wolfenbüttel - Niedersachsen)": "031580000000", + "Am Großen Rhode, gemfr. Gebiet (Wolfenbüttel - Niedersachsen)": "031580000000", + "Barnstorf-Warle, gemfr. Gebiet (Wolfenbüttel - Niedersachsen)": "031580000000", + "Voigtsdahlum, gemfr. Gebiet (Wolfenbüttel - Niedersachsen)": "031580000000", + "Adelebsen, Flecken (Göttingen - Niedersachsen)": "031590000000", + "Bad Grund (Harz) (Göttingen - Niedersachsen)": "031590000000", + "Bad Lauterberg im Harz, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Bad Sachsa, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Bovenden, Flecken (Göttingen - Niedersachsen)": "031590000000", + "Duderstadt, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Friedland (Göttingen - Niedersachsen)": "031590000000", + "Gleichen (Göttingen - Niedersachsen)": "031590000000", + "Göttingen, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Hann. Münden, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Herzberg am Harz, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Osterode am Harz, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Rosdorf (Göttingen - Niedersachsen)": "031590000000", + "Staufenberg (Göttingen - Niedersachsen)": "031590000000", + "Walkenried (Göttingen - Niedersachsen)": "031590000000", + "Bühren (Göttingen - Niedersachsen)": "031590000000", + "Dransfeld, Stadt (Göttingen - Niedersachsen)": "031590000000", + "Jühnde (Göttingen - Niedersachsen)": "031590000000", + "Niemetal (Göttingen - Niedersachsen)": "031590000000", + "Scheden (Göttingen - Niedersachsen)": "031590000000", + "Bilshausen (Göttingen - Niedersachsen)": "031590000000", + "Bodensee (Göttingen - Niedersachsen)": "031590000000", + "Gieboldehausen, Flecken (Göttingen - Niedersachsen)": "031590000000", + "Krebeck (Göttingen - Niedersachsen)": "031590000000", + "Obernfeld (Göttingen - Niedersachsen)": "031590000000", + "Rhumspringe (Göttingen - Niedersachsen)": "031590000000", + "Rollshausen (Göttingen - Niedersachsen)": "031590000000", + "Rüdershausen (Göttingen - Niedersachsen)": "031590000000", + "Wollbrandshausen (Göttingen - Niedersachsen)": "031590000000", + "Wollershausen (Göttingen - Niedersachsen)": "031590000000", + "Elbingerode (Göttingen - Niedersachsen)": "031590000000", + "Hattorf am Harz (Göttingen - Niedersachsen)": "031590000000", + "Hörden am Harz (Göttingen - Niedersachsen)": "031590000000", + "Wulften am Harz (Göttingen - Niedersachsen)": "031590000000", + "Ebergötzen (Göttingen - Niedersachsen)": "031590000000", + "Landolfshausen (Göttingen - Niedersachsen)": "031590000000", + "Seeburg (Göttingen - Niedersachsen)": "031590000000", + "Seulingen (Göttingen - Niedersachsen)": "031590000000", + "Waake (Göttingen - Niedersachsen)": "031590000000", + "Harz (Landkreis Göttingen), gemfr. Geb. (Göttingen - Niedersachsen)": "031590000000", + "Hannover, Landeshauptstadt (Hannover, Region - Niedersachsen)": "032410000000", + "Barsinghausen, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Burgdorf, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Burgwedel, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Garbsen, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Gehrden, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Hemmingen, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Isernhagen (Hannover, Region - Niedersachsen)": "032410000000", + "Laatzen, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Langenhagen, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Lehrte, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Neustadt am Rübenberge, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Pattensen, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Ronnenberg, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Seelze, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Sehnde, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Springe, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Uetze (Hannover, Region - Niedersachsen)": "032410000000", + "Wedemark (Hannover, Region - Niedersachsen)": "032410000000", + "Wennigsen (Deister) (Hannover, Region - Niedersachsen)": "032410000000", + "Wunstorf, Stadt (Hannover, Region - Niedersachsen)": "032410000000", + "Bassum, Stadt (Diepholz - Niedersachsen)": "032510000000", + "Diepholz, Stadt (Diepholz - Niedersachsen)": "032510000000", + "Stuhr (Diepholz - Niedersachsen)": "032510000000", + "Sulingen, Stadt (Diepholz - Niedersachsen)": "032510000000", + "Syke, Stadt (Diepholz - Niedersachsen)": "032510000000", + "Twistringen, Stadt (Diepholz - Niedersachsen)": "032510000000", + "Wagenfeld (Diepholz - Niedersachsen)": "032510000000", + "Weyhe (Diepholz - Niedersachsen)": "032510000000", + "Brockum (Diepholz - Niedersachsen)": "032510000000", + "Hüde (Diepholz - Niedersachsen)": "032510000000", + "Lembruch (Diepholz - Niedersachsen)": "032510000000", + "Lemförde, Flecken (Diepholz - Niedersachsen)": "032510000000", + "Marl (Diepholz - Niedersachsen)": "032510000000", + "Quernheim (Diepholz - Niedersachsen)": "032510000000", + "Stemshorn (Diepholz - Niedersachsen)": "032510000000", + "Barnstorf, Flecken (Diepholz - Niedersachsen)": "032510000000", + "Drebber (Diepholz - Niedersachsen)": "032510000000", + "Drentwede (Diepholz - Niedersachsen)": "032510000000", + "Eydelstedt (Diepholz - Niedersachsen)": "032510000000", + "Asendorf (Diepholz - Niedersachsen)": "032510000000", + "Martfeld (Diepholz - Niedersachsen)": "032510000000", + "Schwarme (Diepholz - Niedersachsen)": "032510000000", + "Bruchhausen-Vilsen, Flecken (Diepholz - Niedersachsen)": "032510000000", + "Bahrenborstel (Diepholz - Niedersachsen)": "032510000000", + "Barenburg, Flecken (Diepholz - Niedersachsen)": "032510000000", + "Freistatt (Diepholz - Niedersachsen)": "032510000000", + "Kirchdorf (Diepholz - Niedersachsen)": "032510000000", + "Varrel (Diepholz - Niedersachsen)": "032510000000", + "Wehrbleck (Diepholz - Niedersachsen)": "032510000000", + "Barver (Diepholz - Niedersachsen)": "032510000000", + "Dickel (Diepholz - Niedersachsen)": "032510000000", + "Hemsloh (Diepholz - Niedersachsen)": "032510000000", + "Rehden (Diepholz - Niedersachsen)": "032510000000", + "Wetschen (Diepholz - Niedersachsen)": "032510000000", + "Affinghausen (Diepholz - Niedersachsen)": "032510000000", + "Ehrenburg (Diepholz - Niedersachsen)": "032510000000", + "Neuenkirchen (Diepholz - Niedersachsen)": "032510000000", + "Scholen (Diepholz - Niedersachsen)": "032510000000", + "Schwaförden (Diepholz - Niedersachsen)": "032510000000", + "Sudwalde (Diepholz - Niedersachsen)": "032510000000", + "Borstel (Diepholz - Niedersachsen)": "032510000000", + "Maasen (Diepholz - Niedersachsen)": "032510000000", + "Mellinghausen (Diepholz - Niedersachsen)": "032510000000", + "Siedenburg, Flecken (Diepholz - Niedersachsen)": "032510000000", + "Staffhorst (Diepholz - Niedersachsen)": "032510000000", + "Aerzen, Flecken (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Bad Münder am Deister, Stadt (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Bad Pyrmont, Stadt (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Coppenbrügge, Flecken (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Emmerthal (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Hameln, Stadt (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Hessisch Oldendorf, Stadt (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Salzhemmendorf, Flecken (Hameln-Pyrmont - Niedersachsen)": "032520000000", + "Alfeld (Leine), Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Algermissen (Hildesheim - Niedersachsen)": "032540000000", + "Bad Salzdetfurth, Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Bockenem, Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Diekholzen (Hildesheim - Niedersachsen)": "032540000000", + "Elze, Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Giesen (Hildesheim - Niedersachsen)": "032540000000", + "Harsum (Hildesheim - Niedersachsen)": "032540000000", + "Hildesheim, Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Holle (Hildesheim - Niedersachsen)": "032540000000", + "Nordstemmen (Hildesheim - Niedersachsen)": "032540000000", + "Sarstedt, Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Schellerten (Hildesheim - Niedersachsen)": "032540000000", + "Söhlde (Hildesheim - Niedersachsen)": "032540000000", + "Freden (Leine) (Hildesheim - Niedersachsen)": "032540000000", + "Lamspringe (Hildesheim - Niedersachsen)": "032540000000", + "Sibbesse (Hildesheim - Niedersachsen)": "032540000000", + "Eime, Flecken (Hildesheim - Niedersachsen)": "032540000000", + "Duingen, Flecken (Hildesheim - Niedersachsen)": "032540000000", + "Gronau (Leine), Stadt (Hildesheim - Niedersachsen)": "032540000000", + "Delligsen, Flecken (Holzminden - Niedersachsen)": "032550000000", + "Holzminden, Stadt (Holzminden - Niedersachsen)": "032550000000", + "Bevern, Flecken (Holzminden - Niedersachsen)": "032550000000", + "Golmbach (Holzminden - Niedersachsen)": "032550000000", + "Holenberg (Holzminden - Niedersachsen)": "032550000000", + "Negenborn (Holzminden - Niedersachsen)": "032550000000", + "Boffzen (Holzminden - Niedersachsen)": "032550000000", + "Derental (Holzminden - Niedersachsen)": "032550000000", + "Fürstenberg (Holzminden - Niedersachsen)": "032550000000", + "Lauenförde, Flecken (Holzminden - Niedersachsen)": "032550000000", + "Bodenwerder, Münchhausenstadt (Holzminden - Niedersachsen)": "032550000000", + "Brevörde (Holzminden - Niedersachsen)": "032550000000", + "Halle (Holzminden - Niedersachsen)": "032550000000", + "Hehlen (Holzminden - Niedersachsen)": "032550000000", + "Heinsen (Holzminden - Niedersachsen)": "032550000000", + "Heyen (Holzminden - Niedersachsen)": "032550000000", + "Kirchbrak (Holzminden - Niedersachsen)": "032550000000", + "Ottenstein, Flecken (Holzminden - Niedersachsen)": "032550000000", + "Pegestorf (Holzminden - Niedersachsen)": "032550000000", + "Polle, Flecken (Holzminden - Niedersachsen)": "032550000000", + "Vahlbruch (Holzminden - Niedersachsen)": "032550000000", + "Arholzen (Holzminden - Niedersachsen)": "032550000000", + "Deensen (Holzminden - Niedersachsen)": "032550000000", + "Dielmissen (Holzminden - Niedersachsen)": "032550000000", + "Eimen (Holzminden - Niedersachsen)": "032550000000", + "Eschershausen, Stadt (Holzminden - Niedersachsen)": "032550000000", + "Heinade (Holzminden - Niedersachsen)": "032550000000", + "Holzen (Holzminden - Niedersachsen)": "032550000000", + "Lenne (Holzminden - Niedersachsen)": "032550000000", + "Lüerdissen (Holzminden - Niedersachsen)": "032550000000", + "Stadtoldendorf, Stadt (Holzminden - Niedersachsen)": "032550000000", + "Wangelnstedt (Holzminden - Niedersachsen)": "032550000000", + "Boffzen, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Eimen, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Eschershausen, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Grünenplan, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Holzminden, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Merxhausen, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Wenzen, gemfr. Gebiet (Holzminden - Niedersachsen)": "032550000000", + "Nienburg (Weser), Stadt (Nienburg/Weser - Niedersachsen)": "032560000000", + "Rehburg-Loccum, Stadt (Nienburg/Weser - Niedersachsen)": "032560000000", + "Steyerberg, Flecken (Nienburg/Weser - Niedersachsen)": "032560000000", + "Drakenburg, Flecken (Nienburg/Weser - Niedersachsen)": "032560000000", + "Haßbergen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Heemsen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Rohrsen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Binnen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Liebenau, Flecken (Nienburg/Weser - Niedersachsen)": "032560000000", + "Pennigsehl (Nienburg/Weser - Niedersachsen)": "032560000000", + "Balge (Nienburg/Weser - Niedersachsen)": "032560000000", + "Marklohe (Nienburg/Weser - Niedersachsen)": "032560000000", + "Wietzen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Linsburg (Nienburg/Weser - Niedersachsen)": "032560000000", + "Rodewald (Nienburg/Weser - Niedersachsen)": "032560000000", + "Steimbke (Nienburg/Weser - Niedersachsen)": "032560000000", + "Stöckse (Nienburg/Weser - Niedersachsen)": "032560000000", + "Diepenau, Flecken (Nienburg/Weser - Niedersachsen)": "032560000000", + "Raddestorf (Nienburg/Weser - Niedersachsen)": "032560000000", + "Uchte, Flecken (Nienburg/Weser - Niedersachsen)": "032560000000", + "Warmsen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Bücken, Flecken (Nienburg/Weser - Niedersachsen)": "032560000000", + "Eystrup (Nienburg/Weser - Niedersachsen)": "032560000000", + "Gandesbergen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Hämelhausen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Hassel (Weser) (Nienburg/Weser - Niedersachsen)": "032560000000", + "Hilgermissen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Hoya, Stadt (Nienburg/Weser - Niedersachsen)": "032560000000", + "Hoyerhagen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Schweringen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Warpe (Nienburg/Weser - Niedersachsen)": "032560000000", + "Estorf (Nienburg/Weser - Niedersachsen)": "032560000000", + "Husum (Nienburg/Weser - Niedersachsen)": "032560000000", + "Landesbergen (Nienburg/Weser - Niedersachsen)": "032560000000", + "Leese (Nienburg/Weser - Niedersachsen)": "032560000000", + "Stolzenau (Nienburg/Weser - Niedersachsen)": "032560000000", + "Auetal (Schaumburg - Niedersachsen)": "032570000000", + "Bückeburg, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Obernkirchen, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Rinteln, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Stadthagen, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Ahnsen (Schaumburg - Niedersachsen)": "032570000000", + "Bad Eilsen (Schaumburg - Niedersachsen)": "032570000000", + "Buchholz (Schaumburg - Niedersachsen)": "032570000000", + "Heeßen (Schaumburg - Niedersachsen)": "032570000000", + "Luhden (Schaumburg - Niedersachsen)": "032570000000", + "Beckedorf (Schaumburg - Niedersachsen)": "032570000000", + "Heuerßen (Schaumburg - Niedersachsen)": "032570000000", + "Lindhorst (Schaumburg - Niedersachsen)": "032570000000", + "Lüdersfeld (Schaumburg - Niedersachsen)": "032570000000", + "Bad Nenndorf, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Haste (Schaumburg - Niedersachsen)": "032570000000", + "Hohnhorst (Schaumburg - Niedersachsen)": "032570000000", + "Suthfeld (Schaumburg - Niedersachsen)": "032570000000", + "Lauenhagen (Schaumburg - Niedersachsen)": "032570000000", + "Meerbeck (Schaumburg - Niedersachsen)": "032570000000", + "Niedernwöhren (Schaumburg - Niedersachsen)": "032570000000", + "Nordsehl (Schaumburg - Niedersachsen)": "032570000000", + "Pollhagen (Schaumburg - Niedersachsen)": "032570000000", + "Wiedensahl, Flecken (Schaumburg - Niedersachsen)": "032570000000", + "Helpsen (Schaumburg - Niedersachsen)": "032570000000", + "Hespe (Schaumburg - Niedersachsen)": "032570000000", + "Nienstädt (Schaumburg - Niedersachsen)": "032570000000", + "Seggebruch (Schaumburg - Niedersachsen)": "032570000000", + "Apelern (Schaumburg - Niedersachsen)": "032570000000", + "Hülsede (Schaumburg - Niedersachsen)": "032570000000", + "Lauenau, Flecken (Schaumburg - Niedersachsen)": "032570000000", + "Messenkamp (Schaumburg - Niedersachsen)": "032570000000", + "Pohle (Schaumburg - Niedersachsen)": "032570000000", + "Rodenberg, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Auhagen (Schaumburg - Niedersachsen)": "032570000000", + "Hagenburg, Flecken (Schaumburg - Niedersachsen)": "032570000000", + "Sachsenhagen, Stadt (Schaumburg - Niedersachsen)": "032570000000", + "Wölpinghausen (Schaumburg - Niedersachsen)": "032570000000", + "Bergen, Stadt (Celle - Niedersachsen)": "033510000000", + "Celle, Stadt (Celle - Niedersachsen)": "033510000000", + "Faßberg (Celle - Niedersachsen)": "033510000000", + "Hambühren (Celle - Niedersachsen)": "033510000000", + "Wietze (Celle - Niedersachsen)": "033510000000", + "Winsen (Aller) (Celle - Niedersachsen)": "033510000000", + "Eschede (Celle - Niedersachsen)": "033510000000", + "Südheide (Celle - Niedersachsen)": "033510000000", + "Bröckel (Celle - Niedersachsen)": "033510000000", + "Eicklingen (Celle - Niedersachsen)": "033510000000", + "Langlingen (Celle - Niedersachsen)": "033510000000", + "Wienhausen, Klostergemeinde (Celle - Niedersachsen)": "033510000000", + "Ahnsbeck (Celle - Niedersachsen)": "033510000000", + "Beedenbostel (Celle - Niedersachsen)": "033510000000", + "Eldingen (Celle - Niedersachsen)": "033510000000", + "Hohne (Celle - Niedersachsen)": "033510000000", + "Lachendorf (Celle - Niedersachsen)": "033510000000", + "Adelheidsdorf (Celle - Niedersachsen)": "033510000000", + "Nienhagen (Celle - Niedersachsen)": "033510000000", + "Wathlingen (Celle - Niedersachsen)": "033510000000", + "Lohheide, gemfr. Bezirk (Celle - Niedersachsen)": "033510000000", + "Cuxhaven, Stadt (Cuxhaven - Niedersachsen)": "033520000000", + "Loxstedt (Cuxhaven - Niedersachsen)": "033520000000", + "Schiffdorf (Cuxhaven - Niedersachsen)": "033520000000", + "Beverstedt (Cuxhaven - Niedersachsen)": "033520000000", + "Hagen im Bremischen (Cuxhaven - Niedersachsen)": "033520000000", + "Wurster Nordseeküste (Cuxhaven - Niedersachsen)": "033520000000", + "Geestland, Stadt (Cuxhaven - Niedersachsen)": "033520000000", + "Armstorf (Cuxhaven - Niedersachsen)": "033520000000", + "Hollnseth (Cuxhaven - Niedersachsen)": "033520000000", + "Lamstedt (Cuxhaven - Niedersachsen)": "033520000000", + "Mittelstenahe (Cuxhaven - Niedersachsen)": "033520000000", + "Stinstedt (Cuxhaven - Niedersachsen)": "033520000000", + "Hechthausen (Cuxhaven - Niedersachsen)": "033520000000", + "Hemmoor, Stadt (Cuxhaven - Niedersachsen)": "033520000000", + "Osten (Cuxhaven - Niedersachsen)": "033520000000", + "Belum (Cuxhaven - Niedersachsen)": "033520000000", + "Bülkau (Cuxhaven - Niedersachsen)": "033520000000", + "Ihlienworth (Cuxhaven - Niedersachsen)": "033520000000", + "Neuenkirchen (Cuxhaven - Niedersachsen)": "033520000000", + "Neuhaus (Oste), Flecken (Cuxhaven - Niedersachsen)": "033520000000", + "Nordleda (Cuxhaven - Niedersachsen)": "033520000000", + "Oberndorf (Cuxhaven - Niedersachsen)": "033520000000", + "Odisheim (Cuxhaven - Niedersachsen)": "033520000000", + "Osterbruch (Cuxhaven - Niedersachsen)": "033520000000", + "Otterndorf, Stadt (Cuxhaven - Niedersachsen)": "033520000000", + "Steinau (Cuxhaven - Niedersachsen)": "033520000000", + "Wanna (Cuxhaven - Niedersachsen)": "033520000000", + "Wingst (Cuxhaven - Niedersachsen)": "033520000000", + "Cadenberge (Cuxhaven - Niedersachsen)": "033520000000", + "Buchholz in der Nordheide, Stadt (Harburg - Niedersachsen)": "033530000000", + "Neu Wulmstorf (Harburg - Niedersachsen)": "033530000000", + "Rosengarten (Harburg - Niedersachsen)": "033530000000", + "Seevetal (Harburg - Niedersachsen)": "033530000000", + "Stelle (Harburg - Niedersachsen)": "033530000000", + "Winsen (Luhe), Stadt (Harburg - Niedersachsen)": "033530000000", + "Drage (Harburg - Niedersachsen)": "033530000000", + "Marschacht (Harburg - Niedersachsen)": "033530000000", + "Tespe (Harburg - Niedersachsen)": "033530000000", + "Asendorf (Harburg - Niedersachsen)": "033530000000", + "Brackel (Harburg - Niedersachsen)": "033530000000", + "Egestorf (Harburg - Niedersachsen)": "033530000000", + "Hanstedt (Harburg - Niedersachsen)": "033530000000", + "Marxen (Harburg - Niedersachsen)": "033530000000", + "Undeloh (Harburg - Niedersachsen)": "033530000000", + "Appel (Harburg - Niedersachsen)": "033530000000", + "Drestedt (Harburg - Niedersachsen)": "033530000000", + "Halvesbostel (Harburg - Niedersachsen)": "033530000000", + "Hollenstedt (Harburg - Niedersachsen)": "033530000000", + "Moisburg (Harburg - Niedersachsen)": "033530000000", + "Regesbostel (Harburg - Niedersachsen)": "033530000000", + "Wenzendorf (Harburg - Niedersachsen)": "033530000000", + "Bendestorf (Harburg - Niedersachsen)": "033530000000", + "Harmstorf (Harburg - Niedersachsen)": "033530000000", + "Jesteburg (Harburg - Niedersachsen)": "033530000000", + "Eyendorf (Harburg - Niedersachsen)": "033530000000", + "Garlstorf (Harburg - Niedersachsen)": "033530000000", + "Garstedt (Harburg - Niedersachsen)": "033530000000", + "Gödenstorf (Harburg - Niedersachsen)": "033530000000", + "Salzhausen (Harburg - Niedersachsen)": "033530000000", + "Toppenstedt (Harburg - Niedersachsen)": "033530000000", + "Vierhöfen (Harburg - Niedersachsen)": "033530000000", + "Wulfsen (Harburg - Niedersachsen)": "033530000000", + "Dohren (Harburg - Niedersachsen)": "033530000000", + "Handeloh (Harburg - Niedersachsen)": "033530000000", + "Heidenau (Harburg - Niedersachsen)": "033530000000", + "Kakenstorf (Harburg - Niedersachsen)": "033530000000", + "Königsmoor (Harburg - Niedersachsen)": "033530000000", + "Otter (Harburg - Niedersachsen)": "033530000000", + "Tostedt (Harburg - Niedersachsen)": "033530000000", + "Welle (Harburg - Niedersachsen)": "033530000000", + "Wistedt (Harburg - Niedersachsen)": "033530000000", + "Gartow, Flecken (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Gorleben (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Höhbeck (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Prezelle (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Schnackenburg, Stadt (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Damnatz (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Dannenberg (Elbe), Stadt (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Göhrde (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Gusborn (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Hitzacker (Elbe), Stadt (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Jameln (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Karwitz (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Langendorf (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Neu Darchau (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Zernien (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Bergen an der Dumme, Flecken (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Clenze, Flecken (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Küsten (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Lemgow (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Luckau (Wendland) (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Lübbow (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Lüchow (Wendland), Stadt (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Schnega (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Trebel (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Waddeweitz (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Woltersdorf (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Wustrow (Wendland), Stadt (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Gartow, gemfr. Gebiet (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Göhrde, gemfr. Gebiet (Lüchow-Dannenberg - Niedersachsen)": "033540000000", + "Adendorf (Lüneburg - Niedersachsen)": "033550000000", + "Bleckede, Stadt (Lüneburg - Niedersachsen)": "033550000000", + "Lüneburg, Hansestadt (Lüneburg - Niedersachsen)": "033550000000", + "Amt Neuhaus (Lüneburg - Niedersachsen)": "033550000000", + "Amelinghausen (Lüneburg - Niedersachsen)": "033550000000", + "Betzendorf (Lüneburg - Niedersachsen)": "033550000000", + "Oldendorf (Luhe) (Lüneburg - Niedersachsen)": "033550000000", + "Rehlingen (Lüneburg - Niedersachsen)": "033550000000", + "Soderstorf (Lüneburg - Niedersachsen)": "033550000000", + "Bardowick, Flecken (Lüneburg - Niedersachsen)": "033550000000", + "Barum (Lüneburg - Niedersachsen)": "033550000000", + "Handorf (Lüneburg - Niedersachsen)": "033550000000", + "Mechtersen (Lüneburg - Niedersachsen)": "033550000000", + "Radbruch (Lüneburg - Niedersachsen)": "033550000000", + "Vögelsen (Lüneburg - Niedersachsen)": "033550000000", + "Wittorf (Lüneburg - Niedersachsen)": "033550000000", + "Boitze (Lüneburg - Niedersachsen)": "033550000000", + "Dahlem (Lüneburg - Niedersachsen)": "033550000000", + "Dahlenburg, Flecken (Lüneburg - Niedersachsen)": "033550000000", + "Nahrendorf (Lüneburg - Niedersachsen)": "033550000000", + "Tosterglope (Lüneburg - Niedersachsen)": "033550000000", + "Kirchgellersen (Lüneburg - Niedersachsen)": "033550000000", + "Reppenstedt (Lüneburg - Niedersachsen)": "033550000000", + "Südergellersen (Lüneburg - Niedersachsen)": "033550000000", + "Westergellersen (Lüneburg - Niedersachsen)": "033550000000", + "Barnstedt (Lüneburg - Niedersachsen)": "033550000000", + "Deutsch Evern (Lüneburg - Niedersachsen)": "033550000000", + "Embsen (Lüneburg - Niedersachsen)": "033550000000", + "Melbeck (Lüneburg - Niedersachsen)": "033550000000", + "Barendorf (Lüneburg - Niedersachsen)": "033550000000", + "Neetze (Lüneburg - Niedersachsen)": "033550000000", + "Reinstorf (Lüneburg - Niedersachsen)": "033550000000", + "Thomasburg (Lüneburg - Niedersachsen)": "033550000000", + "Vastorf (Lüneburg - Niedersachsen)": "033550000000", + "Wendisch Evern (Lüneburg - Niedersachsen)": "033550000000", + "Artlenburg, Flecken (Lüneburg - Niedersachsen)": "033550000000", + "Brietlingen (Lüneburg - Niedersachsen)": "033550000000", + "Echem (Lüneburg - Niedersachsen)": "033550000000", + "Hittbergen (Lüneburg - Niedersachsen)": "033550000000", + "Hohnstorf (Elbe) (Lüneburg - Niedersachsen)": "033550000000", + "Lüdersburg (Lüneburg - Niedersachsen)": "033550000000", + "Rullstorf (Lüneburg - Niedersachsen)": "033550000000", + "Scharnebeck (Lüneburg - Niedersachsen)": "033550000000", + "Grasberg (Osterholz - Niedersachsen)": "033560000000", + "Lilienthal (Osterholz - Niedersachsen)": "033560000000", + "Osterholz-Scharmbeck, Stadt (Osterholz - Niedersachsen)": "033560000000", + "Ritterhude (Osterholz - Niedersachsen)": "033560000000", + "Schwanewede (Osterholz - Niedersachsen)": "033560000000", + "Worpswede (Osterholz - Niedersachsen)": "033560000000", + "Axstedt (Osterholz - Niedersachsen)": "033560000000", + "Hambergen (Osterholz - Niedersachsen)": "033560000000", + "Holste (Osterholz - Niedersachsen)": "033560000000", + "Lübberstedt (Osterholz - Niedersachsen)": "033560000000", + "Vollersode (Osterholz - Niedersachsen)": "033560000000", + "Bremervörde, Stadt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Gnarrenburg (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Rotenburg (Wümme), Stadt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Scheeßel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Visselhövede, Stadt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Bothel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Brockel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hemsbünde (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hemslingen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Kirchwalsede (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Westerwalsede (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Fintel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Helvesiek (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Lauenbrück (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Stemmen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Vahlde (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Alfstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Basdahl (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Ebersdorf (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hipstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Oerel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Anderlingen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Deinstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Farven (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Ostereistedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Rhade (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Sandbostel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Seedorf (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Selsingen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Groß Meckelsen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hamersen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Kalbe (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Klein Meckelsen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Lengenbostel (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Sittensen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Tiste (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Vierden (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Wohnste (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Ahausen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Bötersen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hassendorf (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hellwege (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Horstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Reeßum (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Sottrum (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Breddorf (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Bülstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Hepstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Kirchtimke (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Tarmstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Vorwerk (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Westertimke (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Wilstedt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Elsdorf (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Gyhum (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Heeslingen (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Zeven, Stadt (Rotenburg (Wümme) - Niedersachsen)": "033570000000", + "Bispingen (Heidekreis - Niedersachsen)": "033580000000", + "Bad Fallingbostel, Stadt (Heidekreis - Niedersachsen)": "033580000000", + "Munster, Stadt (Heidekreis - Niedersachsen)": "033580000000", + "Neuenkirchen (Heidekreis - Niedersachsen)": "033580000000", + "Schneverdingen, Stadt (Heidekreis - Niedersachsen)": "033580000000", + "Soltau, Stadt (Heidekreis - Niedersachsen)": "033580000000", + "Wietzendorf (Heidekreis - Niedersachsen)": "033580000000", + "Walsrode, Stadt (Heidekreis - Niedersachsen)": "033580000000", + "Ahlden (Aller), Flecken (Heidekreis - Niedersachsen)": "033580000000", + "Eickeloh (Heidekreis - Niedersachsen)": "033580000000", + "Grethem (Heidekreis - Niedersachsen)": "033580000000", + "Hademstorf (Heidekreis - Niedersachsen)": "033580000000", + "Hodenhagen (Heidekreis - Niedersachsen)": "033580000000", + "Böhme (Heidekreis - Niedersachsen)": "033580000000", + "Frankenfeld (Heidekreis - Niedersachsen)": "033580000000", + "Häuslingen (Heidekreis - Niedersachsen)": "033580000000", + "Rethem (Aller), Stadt (Heidekreis - Niedersachsen)": "033580000000", + "Buchholz (Aller) (Heidekreis - Niedersachsen)": "033580000000", + "Essel (Heidekreis - Niedersachsen)": "033580000000", + "Gilten (Heidekreis - Niedersachsen)": "033580000000", + "Lindwedel (Heidekreis - Niedersachsen)": "033580000000", + "Schwarmstedt (Heidekreis - Niedersachsen)": "033580000000", + "Osterheide, gemfr. Bezirk (Heidekreis - Niedersachsen)": "033580000000", + "Buxtehude, Hansestadt (Stade - Niedersachsen)": "033590000000", + "Drochtersen (Stade - Niedersachsen)": "033590000000", + "Jork (Stade - Niedersachsen)": "033590000000", + "Stade, Hansestadt (Stade - Niedersachsen)": "033590000000", + "Apensen (Stade - Niedersachsen)": "033590000000", + "Beckdorf (Stade - Niedersachsen)": "033590000000", + "Sauensiek (Stade - Niedersachsen)": "033590000000", + "Deinste (Stade - Niedersachsen)": "033590000000", + "Fredenbeck (Stade - Niedersachsen)": "033590000000", + "Kutenholz (Stade - Niedersachsen)": "033590000000", + "Ahlerstedt (Stade - Niedersachsen)": "033590000000", + "Bargstedt (Stade - Niedersachsen)": "033590000000", + "Brest (Stade - Niedersachsen)": "033590000000", + "Harsefeld, Flecken (Stade - Niedersachsen)": "033590000000", + "Agathenburg (Stade - Niedersachsen)": "033590000000", + "Bliedersdorf (Stade - Niedersachsen)": "033590000000", + "Dollern (Stade - Niedersachsen)": "033590000000", + "Horneburg, Flecken (Stade - Niedersachsen)": "033590000000", + "Nottensdorf (Stade - Niedersachsen)": "033590000000", + "Grünendeich (Stade - Niedersachsen)": "033590000000", + "Guderhandviertel (Stade - Niedersachsen)": "033590000000", + "Hollern-Twielenfleth (Stade - Niedersachsen)": "033590000000", + "Mittelnkirchen (Stade - Niedersachsen)": "033590000000", + "Neuenkirchen (Stade - Niedersachsen)": "033590000000", + "Steinkirchen (Stade - Niedersachsen)": "033590000000", + "Balje (Stade - Niedersachsen)": "033590000000", + "Freiburg (Elbe), Flecken (Stade - Niedersachsen)": "033590000000", + "Krummendeich (Stade - Niedersachsen)": "033590000000", + "Oederquart (Stade - Niedersachsen)": "033590000000", + "Wischhafen (Stade - Niedersachsen)": "033590000000", + "Burweg (Stade - Niedersachsen)": "033590000000", + "Düdenbüttel (Stade - Niedersachsen)": "033590000000", + "Engelschoff (Stade - Niedersachsen)": "033590000000", + "Estorf (Stade - Niedersachsen)": "033590000000", + "Großenwörden (Stade - Niedersachsen)": "033590000000", + "Hammah (Stade - Niedersachsen)": "033590000000", + "Heinbockel (Stade - Niedersachsen)": "033590000000", + "Himmelpforten (Stade - Niedersachsen)": "033590000000", + "Kranenburg (Stade - Niedersachsen)": "033590000000", + "Oldendorf (Stade - Niedersachsen)": "033590000000", + "Bienenbüttel (Uelzen - Niedersachsen)": "033600000000", + "Uelzen, Hansestadt (Uelzen - Niedersachsen)": "033600000000", + "Oetzen (Uelzen - Niedersachsen)": "033600000000", + "Rätzlingen (Uelzen - Niedersachsen)": "033600000000", + "Rosche (Uelzen - Niedersachsen)": "033600000000", + "Stoetze (Uelzen - Niedersachsen)": "033600000000", + "Suhlendorf (Uelzen - Niedersachsen)": "033600000000", + "Eimke (Uelzen - Niedersachsen)": "033600000000", + "Gerdau (Uelzen - Niedersachsen)": "033600000000", + "Suderburg (Uelzen - Niedersachsen)": "033600000000", + "Altenmedingen (Uelzen - Niedersachsen)": "033600000000", + "Bad Bevensen, Stadt (Uelzen - Niedersachsen)": "033600000000", + "Barum (Uelzen - Niedersachsen)": "033600000000", + "Ebstorf,Klosterflecken (Uelzen - Niedersachsen)": "033600000000", + "Emmendorf (Uelzen - Niedersachsen)": "033600000000", + "Hanstedt (Uelzen - Niedersachsen)": "033600000000", + "Himbergen (Uelzen - Niedersachsen)": "033600000000", + "Jelmstorf (Uelzen - Niedersachsen)": "033600000000", + "Natendorf (Uelzen - Niedersachsen)": "033600000000", + "Römstedt (Uelzen - Niedersachsen)": "033600000000", + "Schwienau (Uelzen - Niedersachsen)": "033600000000", + "Weste (Uelzen - Niedersachsen)": "033600000000", + "Wriedel (Uelzen - Niedersachsen)": "033600000000", + "Bad Bodenteich, Flecken (Uelzen - Niedersachsen)": "033600000000", + "Lüder (Uelzen - Niedersachsen)": "033600000000", + "Soltendieck (Uelzen - Niedersachsen)": "033600000000", + "Wrestedt (Uelzen - Niedersachsen)": "033600000000", + "Achim, Stadt (Verden - Niedersachsen)": "033610000000", + "Dörverden (Verden - Niedersachsen)": "033610000000", + "Kirchlinteln (Verden - Niedersachsen)": "033610000000", + "Langwedel, Flecken (Verden - Niedersachsen)": "033610000000", + "Ottersberg, Flecken (Verden - Niedersachsen)": "033610000000", + "Oyten (Verden - Niedersachsen)": "033610000000", + "Verden (Aller), Stadt (Verden - Niedersachsen)": "033610000000", + "Blender (Verden - Niedersachsen)": "033610000000", + "Emtinghausen (Verden - Niedersachsen)": "033610000000", + "Riede (Verden - Niedersachsen)": "033610000000", + "Thedinghausen (Verden - Niedersachsen)": "033610000000", + "Delmenhorst, Stadt": "034010000000", + "Emden, Stadt": "034020000000", + "Oldenburg (Oldenburg), Stadt": "034030000000", + "Osnabrück, Stadt": "034040000000", + "Wilhelmshaven, Stadt": "034050000000", + "Apen (Ammerland - Niedersachsen)": "034510000000", + "Bad Zwischenahn (Ammerland - Niedersachsen)": "034510000000", + "Edewecht (Ammerland - Niedersachsen)": "034510000000", + "Rastede (Ammerland - Niedersachsen)": "034510000000", + "Westerstede, Stadt (Ammerland - Niedersachsen)": "034510000000", + "Wiefelstede (Ammerland - Niedersachsen)": "034510000000", + "Aurich, Stadt (Aurich - Niedersachsen)": "034520000000", + "Baltrum (Aurich - Niedersachsen)": "034520000000", + "Großefehn (Aurich - Niedersachsen)": "034520000000", + "Großheide (Aurich - Niedersachsen)": "034520000000", + "Hinte (Aurich - Niedersachsen)": "034520000000", + "Ihlow (Aurich - Niedersachsen)": "034520000000", + "Juist, Inselgemeinde (Aurich - Niedersachsen)": "034520000000", + "Krummhörn (Aurich - Niedersachsen)": "034520000000", + "Norden, Stadt (Aurich - Niedersachsen)": "034520000000", + "Norderney, Stadt (Aurich - Niedersachsen)": "034520000000", + "Südbrookmerland (Aurich - Niedersachsen)": "034520000000", + "Wiesmoor, Stadt (Aurich - Niedersachsen)": "034520000000", + "Dornum (Aurich - Niedersachsen)": "034520000000", + "Leezdorf (Aurich - Niedersachsen)": "034520000000", + "Marienhafe, Flecken (Aurich - Niedersachsen)": "034520000000", + "Osteel (Aurich - Niedersachsen)": "034520000000", + "Rechtsupweg (Aurich - Niedersachsen)": "034520000000", + "Upgant-Schott (Aurich - Niedersachsen)": "034520000000", + "Wirdum (Aurich - Niedersachsen)": "034520000000", + "Berumbur (Aurich - Niedersachsen)": "034520000000", + "Hage, Flecken (Aurich - Niedersachsen)": "034520000000", + "Hagermarsch (Aurich - Niedersachsen)": "034520000000", + "Halbemond (Aurich - Niedersachsen)": "034520000000", + "Lütetsburg (Aurich - Niedersachsen)": "034520000000", + "Nordseeinsel Memmert, gemfr. Gebiet (Aurich - Niedersachsen)": "034520000000", + "Barßel (Cloppenburg - Niedersachsen)": "034530000000", + "Bösel (Cloppenburg - Niedersachsen)": "034530000000", + "Cappeln (Oldenburg) (Cloppenburg - Niedersachsen)": "034530000000", + "Cloppenburg, Stadt (Cloppenburg - Niedersachsen)": "034530000000", + "Emstek (Cloppenburg - Niedersachsen)": "034530000000", + "Essen (Oldenburg) (Cloppenburg - Niedersachsen)": "034530000000", + "Friesoythe, Stadt (Cloppenburg - Niedersachsen)": "034530000000", + "Garrel (Cloppenburg - Niedersachsen)": "034530000000", + "Lastrup (Cloppenburg - Niedersachsen)": "034530000000", + "Lindern (Oldenburg) (Cloppenburg - Niedersachsen)": "034530000000", + "Löningen, Stadt (Cloppenburg - Niedersachsen)": "034530000000", + "Molbergen (Cloppenburg - Niedersachsen)": "034530000000", + "Saterland (Cloppenburg - Niedersachsen)": "034530000000", + "Emsbüren (Emsland - Niedersachsen)": "034540000000", + "Geeste (Emsland - Niedersachsen)": "034540000000", + "Haren (Ems), Stadt (Emsland - Niedersachsen)": "034540000000", + "Haselünne, Stadt (Emsland - Niedersachsen)": "034540000000", + "Lingen (Ems), Stadt (Emsland - Niedersachsen)": "034540000000", + "Meppen, Stadt (Emsland - Niedersachsen)": "034540000000", + "Papenburg, Stadt (Emsland - Niedersachsen)": "034540000000", + "Rhede (Ems) (Emsland - Niedersachsen)": "034540000000", + "Salzbergen (Emsland - Niedersachsen)": "034540000000", + "Twist (Emsland - Niedersachsen)": "034540000000", + "Dersum (Emsland - Niedersachsen)": "034540000000", + "Dörpen (Emsland - Niedersachsen)": "034540000000", + "Heede (Emsland - Niedersachsen)": "034540000000", + "Kluse (Emsland - Niedersachsen)": "034540000000", + "Lehe (Emsland - Niedersachsen)": "034540000000", + "Neubörger (Emsland - Niedersachsen)": "034540000000", + "Neulehe (Emsland - Niedersachsen)": "034540000000", + "Walchum (Emsland - Niedersachsen)": "034540000000", + "Wippingen (Emsland - Niedersachsen)": "034540000000", + "Andervenne (Emsland - Niedersachsen)": "034540000000", + "Beesten (Emsland - Niedersachsen)": "034540000000", + "Freren, Stadt (Emsland - Niedersachsen)": "034540000000", + "Messingen (Emsland - Niedersachsen)": "034540000000", + "Thuine (Emsland - Niedersachsen)": "034540000000", + "Dohren (Emsland - Niedersachsen)": "034540000000", + "Herzlake (Emsland - Niedersachsen)": "034540000000", + "Lähden (Emsland - Niedersachsen)": "034540000000", + "Fresenburg (Emsland - Niedersachsen)": "034540000000", + "Lathen (Emsland - Niedersachsen)": "034540000000", + "Niederlangen (Emsland - Niedersachsen)": "034540000000", + "Oberlangen (Emsland - Niedersachsen)": "034540000000", + "Renkenberge (Emsland - Niedersachsen)": "034540000000", + "Sustrum (Emsland - Niedersachsen)": "034540000000", + "Bawinkel (Emsland - Niedersachsen)": "034540000000", + "Gersten (Emsland - Niedersachsen)": "034540000000", + "Handrup (Emsland - Niedersachsen)": "034540000000", + "Langen (Emsland - Niedersachsen)": "034540000000", + "Lengerich (Emsland - Niedersachsen)": "034540000000", + "Wettrup (Emsland - Niedersachsen)": "034540000000", + "Bockhorst (Emsland - Niedersachsen)": "034540000000", + "Breddenberg (Emsland - Niedersachsen)": "034540000000", + "Esterwegen (Emsland - Niedersachsen)": "034540000000", + "Hilkenbrook (Emsland - Niedersachsen)": "034540000000", + "Surwold (Emsland - Niedersachsen)": "034540000000", + "Börger (Emsland - Niedersachsen)": "034540000000", + "Groß Berßen (Emsland - Niedersachsen)": "034540000000", + "Hüven (Emsland - Niedersachsen)": "034540000000", + "Klein Berßen (Emsland - Niedersachsen)": "034540000000", + "Sögel (Emsland - Niedersachsen)": "034540000000", + "Spahnharrenstätte (Emsland - Niedersachsen)": "034540000000", + "Stavern (Emsland - Niedersachsen)": "034540000000", + "Werpeloh (Emsland - Niedersachsen)": "034540000000", + "Lünne (Emsland - Niedersachsen)": "034540000000", + "Schapen (Emsland - Niedersachsen)": "034540000000", + "Spelle (Emsland - Niedersachsen)": "034540000000", + "Lahn (Emsland - Niedersachsen)": "034540000000", + "Lorup (Emsland - Niedersachsen)": "034540000000", + "Rastdorf (Emsland - Niedersachsen)": "034540000000", + "Vrees (Emsland - Niedersachsen)": "034540000000", + "Werlte, Stadt (Emsland - Niedersachsen)": "034540000000", + "Jever, Stadt (Friesland - Niedersachsen)": "034550000000", + "Sande (Friesland - Niedersachsen)": "034550000000", + "Schortens, Stadt (Friesland - Niedersachsen)": "034550000000", + "Wangerland (Friesland - Niedersachsen)": "034550000000", + "Wangerooge, Nordseebad (Friesland - Niedersachsen)": "034550000000", + "Bockhorn (Friesland - Niedersachsen)": "034550000000", + "Varel, Stadt (Friesland - Niedersachsen)": "034550000000", + "Zetel (Friesland - Niedersachsen)": "034550000000", + "Bad Bentheim, Stadt (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Nordhorn, Stadt (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Wietmarschen (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Emlichheim (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Hoogstede (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Laar (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Ringe (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Esche (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Georgsdorf (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Lage (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Neuenhaus, Stadt (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Osterwald (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Engden (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Isterberg (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Ohne (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Quendorf (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Samern (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Schüttorf, Stadt (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Getelo (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Gölenkamp (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Halle (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Itterbeck (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Uelsen (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Wielen (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Wilsum (Grafschaft Bentheim - Niedersachsen)": "034560000000", + "Borkum, Stadt (Leer - Niedersachsen)": "034570000000", + "Jemgum (Leer - Niedersachsen)": "034570000000", + "Leer (Ostfriesland), Stadt (Leer - Niedersachsen)": "034570000000", + "Moormerland (Leer - Niedersachsen)": "034570000000", + "Ostrhauderfehn (Leer - Niedersachsen)": "034570000000", + "Rhauderfehn (Leer - Niedersachsen)": "034570000000", + "Uplengen (Leer - Niedersachsen)": "034570000000", + "Weener, Stadt (Leer - Niedersachsen)": "034570000000", + "Westoverledingen (Leer - Niedersachsen)": "034570000000", + "Bunde (Leer - Niedersachsen)": "034570000000", + "Brinkum (Leer - Niedersachsen)": "034570000000", + "Firrel (Leer - Niedersachsen)": "034570000000", + "Hesel (Leer - Niedersachsen)": "034570000000", + "Holtland (Leer - Niedersachsen)": "034570000000", + "Neukamperfehn (Leer - Niedersachsen)": "034570000000", + "Schwerinsdorf (Leer - Niedersachsen)": "034570000000", + "Detern, Flecken (Leer - Niedersachsen)": "034570000000", + "Filsum (Leer - Niedersachsen)": "034570000000", + "Nortmoor (Leer - Niedersachsen)": "034570000000", + "Insel Lütje Hörn, gemfr. Gebiet (Leer - Niedersachsen)": "034570000000", + "Dötlingen (Oldenburg - Niedersachsen)": "034580000000", + "Ganderkesee (Oldenburg - Niedersachsen)": "034580000000", + "Großenkneten (Oldenburg - Niedersachsen)": "034580000000", + "Hatten (Oldenburg - Niedersachsen)": "034580000000", + "Hude (Oldb) (Oldenburg - Niedersachsen)": "034580000000", + "Wardenburg (Oldenburg - Niedersachsen)": "034580000000", + "Wildeshausen, Stadt (Oldenburg - Niedersachsen)": "034580000000", + "Beckeln (Oldenburg - Niedersachsen)": "034580000000", + "Colnrade (Oldenburg - Niedersachsen)": "034580000000", + "Dünsen (Oldenburg - Niedersachsen)": "034580000000", + "Groß Ippener (Oldenburg - Niedersachsen)": "034580000000", + "Harpstedt, Flecken (Oldenburg - Niedersachsen)": "034580000000", + "Kirchseelte (Oldenburg - Niedersachsen)": "034580000000", + "Prinzhöfte (Oldenburg - Niedersachsen)": "034580000000", + "Winkelsett (Oldenburg - Niedersachsen)": "034580000000", + "Bad Essen (Osnabrück - Niedersachsen)": "034590000000", + "Bad Iburg, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Bad Laer (Osnabrück - Niedersachsen)": "034590000000", + "Bad Rothenfelde (Osnabrück - Niedersachsen)": "034590000000", + "Belm (Osnabrück - Niedersachsen)": "034590000000", + "Bissendorf (Osnabrück - Niedersachsen)": "034590000000", + "Bohmte (Osnabrück - Niedersachsen)": "034590000000", + "Bramsche, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Dissen am Teutoburger Wald, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Georgsmarienhütte, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Hagen am Teutoburger Wald (Osnabrück - Niedersachsen)": "034590000000", + "Hasbergen (Osnabrück - Niedersachsen)": "034590000000", + "Hilter am Teutoburger Wald (Osnabrück - Niedersachsen)": "034590000000", + "Melle, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Ostercappeln (Osnabrück - Niedersachsen)": "034590000000", + "Wallenhorst (Osnabrück - Niedersachsen)": "034590000000", + "Glandorf (Osnabrück - Niedersachsen)": "034590000000", + "Badbergen (Osnabrück - Niedersachsen)": "034590000000", + "Menslage (Osnabrück - Niedersachsen)": "034590000000", + "Nortrup (Osnabrück - Niedersachsen)": "034590000000", + "Quakenbrück, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Alfhausen (Osnabrück - Niedersachsen)": "034590000000", + "Ankum (Osnabrück - Niedersachsen)": "034590000000", + "Bersenbrück, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Eggermühlen (Osnabrück - Niedersachsen)": "034590000000", + "Gehrde (Osnabrück - Niedersachsen)": "034590000000", + "Kettenkamp (Osnabrück - Niedersachsen)": "034590000000", + "Rieste (Osnabrück - Niedersachsen)": "034590000000", + "Berge (Osnabrück - Niedersachsen)": "034590000000", + "Bippen (Osnabrück - Niedersachsen)": "034590000000", + "Fürstenau, Stadt (Osnabrück - Niedersachsen)": "034590000000", + "Merzen (Osnabrück - Niedersachsen)": "034590000000", + "Neuenkirchen (Osnabrück - Niedersachsen)": "034590000000", + "Voltlage (Osnabrück - Niedersachsen)": "034590000000", + "Bakum (Vechta - Niedersachsen)": "034600000000", + "Damme, Stadt (Vechta - Niedersachsen)": "034600000000", + "Dinklage, Stadt (Vechta - Niedersachsen)": "034600000000", + "Goldenstedt (Vechta - Niedersachsen)": "034600000000", + "Holdorf (Vechta - Niedersachsen)": "034600000000", + "Lohne (Oldenburg), Stadt (Vechta - Niedersachsen)": "034600000000", + "Neuenkirchen-Vörden (Vechta - Niedersachsen)": "034600000000", + "Steinfeld (Oldenburg) (Vechta - Niedersachsen)": "034600000000", + "Vechta, Stadt (Vechta - Niedersachsen)": "034600000000", + "Visbek (Vechta - Niedersachsen)": "034600000000", + "Berne (Wesermarsch - Niedersachsen)": "034610000000", + "Brake (Unterweser), Stadt (Wesermarsch - Niedersachsen)": "034610000000", + "Butjadingen (Wesermarsch - Niedersachsen)": "034610000000", + "Elsfleth, Stadt (Wesermarsch - Niedersachsen)": "034610000000", + "Jade (Wesermarsch - Niedersachsen)": "034610000000", + "Lemwerder (Wesermarsch - Niedersachsen)": "034610000000", + "Nordenham, Stadt (Wesermarsch - Niedersachsen)": "034610000000", + "Ovelgönne (Wesermarsch - Niedersachsen)": "034610000000", + "Stadland (Wesermarsch - Niedersachsen)": "034610000000", + "Friedeburg (Wittmund - Niedersachsen)": "034620000000", + "Langeoog (Wittmund - Niedersachsen)": "034620000000", + "Spiekeroog (Wittmund - Niedersachsen)": "034620000000", + "Wittmund, Stadt (Wittmund - Niedersachsen)": "034620000000", + "Dunum (Wittmund - Niedersachsen)": "034620000000", + "Esens, Stadt (Wittmund - Niedersachsen)": "034620000000", + "Holtgast (Wittmund - Niedersachsen)": "034620000000", + "Moorweg (Wittmund - Niedersachsen)": "034620000000", + "Neuharlingersiel (Wittmund - Niedersachsen)": "034620000000", + "Stedesdorf (Wittmund - Niedersachsen)": "034620000000", + "Werdum (Wittmund - Niedersachsen)": "034620000000", + "Blomberg (Wittmund - Niedersachsen)": "034620000000", + "Eversmeer (Wittmund - Niedersachsen)": "034620000000", + "Nenndorf (Wittmund - Niedersachsen)": "034620000000", + "Neuschoo (Wittmund - Niedersachsen)": "034620000000", + "Ochtersum (Wittmund - Niedersachsen)": "034620000000", + "Schweindorf (Wittmund - Niedersachsen)": "034620000000", + "Utarp (Wittmund - Niedersachsen)": "034620000000", + "Westerholt (Wittmund - Niedersachsen)": "034620000000", + "Nds-Küstengewässer(Gemarkung Nordsee)": "039010000000", + "Bremen, Stadt": "040110000000", + "Altstadt": "040110000000", + "Bahnhofsvorstadt": "040110000000", + "Ostertor": "040110000000", + "Industriehäfen": "040110000000", + "Stadtbremisches Überseehafengebiet Bremerhaven": "040110000000", + "Neustädter Hafen": "040110000000", + "Hohentorshafen": "040110000000", + "Alte Neustadt": "040110000000", + "Hohentor": "040110000000", + "Neustadt": "040110000000", + "Südervorstadt": "040110000000", + "Gartenstadt Süd": "040110000000", + "Buntentor": "040110000000", + "Neuenland": "040110000000", + "Huckelriede": "040110000000", + "Habenhausen": "040110000000", + "Arsten": "040110000000", + "Kattenturm": "040110000000", + "Kattenesch": "040110000000", + "Mittelshuchting": "040110000000", + "Sodenmatt": "040110000000", + "Kirchhuchting": "040110000000", + "Grolland": "040110000000", + "Woltmershausen": "040110000000", + "Rablinghausen": "040110000000", + "Seehausen": "040110000000", + "Strom": "040110000000", + "Steintor": "040110000000", + "Fesenfeld": "040110000000", + "Peterswerder": "040110000000", + "Hulsberg": "040110000000", + "Neu-Schwachhausen": "040110000000", + "Bürgerpark": "040110000000", + "Barkhof": "040110000000", + "Riensberg": "040110000000", + "Radio Bremen": "040110000000", + "Schwachhausen": "040110000000", + "Gete": "040110000000", + "Gartenstadt Vahr": "040110000000", + "Neue Vahr Nord": "040110000000", + "Neue Vahr Südwest": "040110000000", + "Neue Vahr Südost": "040110000000", + "Horn": "040110000000", + "Lehe": "040110000000", + "Lehesterdeich": "040110000000", + "Borgfeld": "040110000000", + "Oberneuland": "040110000000", + "Ellener Feld": "040110000000", + "Ellenerbrok-Schevemoor": "040110000000", + "Tenever": "040110000000", + "Osterholz": "040110000000", + "Blockdiek": "040110000000", + "Sebaldsbrück": "040110000000", + "Hastedt": "040110000000", + "Hemelingen": "040110000000", + "Arbergen": "040110000000", + "Mahndorf": "040110000000", + "Blockland": "040110000000", + "Regensburger Straße": "040110000000", + "Findorff-Bürgerweide": "040110000000", + "Weidedamm": "040110000000", + "In den Hufen": "040110000000", + "Utbremen": "040110000000", + "Steffensweg": "040110000000", + "Westend": "040110000000", + "Walle": "040110000000", + "Osterfeuerberg": "040110000000", + "Hohweg": "040110000000", + "Überseestadt": "040110000000", + "Lindenhof": "040110000000", + "Gröpelingen": "040110000000", + "Ohlenhof": "040110000000", + "In den Wischen": "040110000000", + "Oslebshausen": "040110000000", + "Burg-Grambke": "040110000000", + "Werderland": "040110000000", + "Burgdamm": "040110000000", + "Lesum": "040110000000", + "St. Magnus": "040110000000", + "Vegesack": "040110000000", + "Grohn": "040110000000", + "Schönebeck": "040110000000", + "Aumund-Hammersbeck": "040110000000", + "Fähr-Lobbendorf": "040110000000", + "Blumenthal": "040110000000", + "Rönnebeck": "040110000000", + "Lüssum-Bockhorn": "040110000000", + "Farge": "040110000000", + "Rekum": "040110000000", + "Bremerhaven, Stadt": "040120000000", + "Düsseldorf, Stadt": "051110000000", + "Duisburg, Stadt": "051120000000", + "Essen, Stadt": "051130000000", + "Krefeld, Stadt": "051140000000", + "Mönchengladbach, Stadt": "051160000000", + "Mülheim an der Ruhr, Stadt": "051170000000", + "Oberhausen, Stadt": "051190000000", + "Remscheid, Stadt": "051200000000", + "Solingen, Klingenstadt": "051220000000", + "Wuppertal, Stadt": "051240000000", + "Bedburg-Hau (Kleve - Nordrhein-Westfalen)": "051540000000", + "Emmerich am Rhein, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Geldern, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Goch, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Issum (Kleve - Nordrhein-Westfalen)": "051540000000", + "Kalkar, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Kerken (Kleve - Nordrhein-Westfalen)": "051540000000", + "Kevelaer, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Kleve, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Kranenburg (Kleve - Nordrhein-Westfalen)": "051540000000", + "Rees, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Rheurdt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Straelen, Stadt (Kleve - Nordrhein-Westfalen)": "051540000000", + "Uedem (Kleve - Nordrhein-Westfalen)": "051540000000", + "Wachtendonk (Kleve - Nordrhein-Westfalen)": "051540000000", + "Weeze (Kleve - Nordrhein-Westfalen)": "051540000000", + "Erkrath, Fundort des Neanderthalers, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Haan, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Heiligenhaus, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Hilden, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Langenfeld (Rheinland), Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Mettmann, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Monheim am Rhein, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Ratingen, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Velbert, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Wülfrath, Stadt (Mettmann - Nordrhein-Westfalen)": "051580000000", + "Dormagen, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Grevenbroich, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Jüchen, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Kaarst, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Korschenbroich, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Meerbusch, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Neuss, Stadt (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Rommerskirchen (Rhein-Kreis Neuss - Nordrhein-Westfalen)": "051620000000", + "Brüggen, Burggemeinde (Viersen - Nordrhein-Westfalen)": "051660000000", + "Grefrath, Sport- und Freizeitgemeinde (Viersen - Nordrhein-Westfalen)": "051660000000", + "Kempen, Stadt (Viersen - Nordrhein-Westfalen)": "051660000000", + "Nettetal, Stadt (Viersen - Nordrhein-Westfalen)": "051660000000", + "Niederkrüchten (Viersen - Nordrhein-Westfalen)": "051660000000", + "Schwalmtal (Viersen - Nordrhein-Westfalen)": "051660000000", + "Tönisvorst, Stadt (Viersen - Nordrhein-Westfalen)": "051660000000", + "Viersen, Stadt (Viersen - Nordrhein-Westfalen)": "051660000000", + "Willich, Stadt (Viersen - Nordrhein-Westfalen)": "051660000000", + "Alpen (Wesel - Nordrhein-Westfalen)": "051700000000", + "Dinslaken, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Hamminkeln, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Hünxe (Wesel - Nordrhein-Westfalen)": "051700000000", + "Kamp-Lintfort, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Moers, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Neukirchen-Vluyn, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Rheinberg, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Schermbeck (Wesel - Nordrhein-Westfalen)": "051700000000", + "Sonsbeck (Wesel - Nordrhein-Westfalen)": "051700000000", + "Voerde (Niederrhein), Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Wesel, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Xanten, Stadt (Wesel - Nordrhein-Westfalen)": "051700000000", + "Bonn, Stadt": "053140000000", + "Köln, Stadt": "053150000000", + "Leverkusen, Stadt": "053160000000", + "Aachen, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Alsdorf, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Baesweiler, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Eschweiler, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Herzogenrath, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Monschau, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Roetgen, Tor zur Eifel (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Simmerath (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Stolberg (Rhld.), Kupferstadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Würselen, Stadt (Aachen, Städteregion - Nordrhein-Westfalen)": "053340000000", + "Aldenhoven (Düren - Nordrhein-Westfalen)": "053580000000", + "Düren, Stadt (Düren - Nordrhein-Westfalen)": "053580000000", + "Heimbach, Stadt (Düren - Nordrhein-Westfalen)": "053580000000", + "Hürtgenwald (Düren - Nordrhein-Westfalen)": "053580000000", + "Inden (Düren - Nordrhein-Westfalen)": "053580000000", + "Jülich, Stadt (Düren - Nordrhein-Westfalen)": "053580000000", + "Kreuzau (Düren - Nordrhein-Westfalen)": "053580000000", + "Langerwehe (Düren - Nordrhein-Westfalen)": "053580000000", + "Linnich, Stadt (Düren - Nordrhein-Westfalen)": "053580000000", + "Merzenich (Düren - Nordrhein-Westfalen)": "053580000000", + "Nideggen, Stadt (Düren - Nordrhein-Westfalen)": "053580000000", + "Niederzier (Düren - Nordrhein-Westfalen)": "053580000000", + "Nörvenich (Düren - Nordrhein-Westfalen)": "053580000000", + "Titz (Düren - Nordrhein-Westfalen)": "053580000000", + "Vettweiß (Düren - Nordrhein-Westfalen)": "053580000000", + "Bedburg, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Bergheim, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Brühl, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Elsdorf, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Erftstadt, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Frechen, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Hürth, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Kerpen, Kolpingstadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Pulheim, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Wesseling, Stadt (Rhein-Erft-Kreis - Nordrhein-Westfalen)": "053620000000", + "Bad Münstereifel, Stadt (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Blankenheim (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Dahlem (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Euskirchen, Stadt (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Hellenthal (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Kall (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Mechernich, Stadt (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Nettersheim (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Schleiden, Stadt (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Weilerswist (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Zülpich, Stadt (Euskirchen - Nordrhein-Westfalen)": "053660000000", + "Erkelenz, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Gangelt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Geilenkirchen, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Heinsberg, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Hückelhoven, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Selfkant (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Übach-Palenberg, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Waldfeucht (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Wassenberg, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Wegberg, Stadt (Heinsberg - Nordrhein-Westfalen)": "053700000000", + "Bergneustadt, Stadt (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Engelskirchen (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Gummersbach, Stadt (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Hückeswagen, Schloss-Stadt (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Lindlar (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Marienheide (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Morsbach (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Nümbrecht (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Radevormwald, Stadt auf der Höhe (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Reichshof (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Waldbröl, Stadt (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Wiehl, Stadt (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Wipperfürth, Hansestadt (Oberbergischer Kreis - Nordrhein-Westfalen)": "053740000000", + "Bergisch Gladbach, Stadt (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Burscheid, Stadt (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Kürten (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Leichlingen (Rheinland), Blütenstadt (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Odenthal (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Overath, Stadt (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Rösrath, Stadt (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Wermelskirchen, Stadt (Rheinisch-Bergischer Kreis - Nordrhein-Westfalen)": "053780000000", + "Alfter (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Bad Honnef, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Bornheim, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Eitorf (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Hennef (Sieg), Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Königswinter, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Lohmar, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Meckenheim, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Much (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Neunkirchen-Seelscheid (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Niederkassel, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Rheinbach, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Ruppichteroth (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Sankt Augustin, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Siegburg, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Swisttal (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Troisdorf, Stadt (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Wachtberg (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Windeck (Rhein-Sieg-Kreis - Nordrhein-Westfalen)": "053820000000", + "Bottrop, Stadt": "055120000000", + "Gelsenkirchen, Stadt": "055130000000", + "Münster, Stadt": "055150000000", + "Ahaus, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Bocholt, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Borken, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Gescher, Glockenstadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Gronau (Westf.), Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Heek (Borken - Nordrhein-Westfalen)": "055540000000", + "Heiden (Borken - Nordrhein-Westfalen)": "055540000000", + "Isselburg, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Legden (Borken - Nordrhein-Westfalen)": "055540000000", + "Raesfeld (Borken - Nordrhein-Westfalen)": "055540000000", + "Reken (Borken - Nordrhein-Westfalen)": "055540000000", + "Rhede, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Schöppingen (Borken - Nordrhein-Westfalen)": "055540000000", + "Stadtlohn, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Südlohn (Borken - Nordrhein-Westfalen)": "055540000000", + "Velen, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Vreden, Stadt (Borken - Nordrhein-Westfalen)": "055540000000", + "Ascheberg (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Billerbeck, Stadt (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Coesfeld, Stadt (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Dülmen, Stadt (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Havixbeck (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Lüdinghausen, Stadt (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Nordkirchen (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Nottuln (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Olfen, Stadt (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Rosendahl (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Senden (Coesfeld - Nordrhein-Westfalen)": "055580000000", + "Castrop-Rauxel, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Datteln, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Dorsten, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Gladbeck, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Haltern am See, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Herten, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Marl, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Oer-Erkenschwick, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Recklinghausen, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Waltrop, Stadt (Recklinghausen - Nordrhein-Westfalen)": "055620000000", + "Altenberge (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Emsdetten, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Greven, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Hörstel, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Hopsten (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Horstmar, Stadt der Burgmannshöfe (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Ibbenbüren, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Ladbergen (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Laer (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Lengerich, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Lienen (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Lotte (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Metelen (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Mettingen (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Neuenkirchen (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Nordwalde (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Ochtrup, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Recke (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Rheine, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Saerbeck, NRW-Klimakommune (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Steinfurt, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Tecklenburg, Stadt (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Westerkappeln (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Wettringen (Steinfurt - Nordrhein-Westfalen)": "055660000000", + "Ahlen, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Beckum, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Beelen (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Drensteinfurt, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Ennigerloh, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Everswinkel (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Oelde, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Ostbevern (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Sassenberg, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Sendenhorst, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Telgte, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Wadersloh (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Warendorf, Stadt (Warendorf - Nordrhein-Westfalen)": "055700000000", + "Bielefeld, Stadt": "057110000000", + "Borgholzhausen, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Gütersloh, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Halle (Westf.), Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Harsewinkel, Die Mähdrescherstadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Herzebrock-Clarholz (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Langenberg (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Rheda-Wiedenbrück, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Rietberg, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Schloß Holte-Stukenbrock, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Steinhagen (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Verl, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Versmold, Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Werther (Westf.), Stadt (Gütersloh - Nordrhein-Westfalen)": "057540000000", + "Bünde, Stadt (Herford - Nordrhein-Westfalen)": "057580000000", + "Enger, Widukindstadt (Herford - Nordrhein-Westfalen)": "057580000000", + "Herford, Hansestadt (Herford - Nordrhein-Westfalen)": "057580000000", + "Hiddenhausen (Herford - Nordrhein-Westfalen)": "057580000000", + "Kirchlengern (Herford - Nordrhein-Westfalen)": "057580000000", + "Löhne, Stadt (Herford - Nordrhein-Westfalen)": "057580000000", + "Rödinghausen (Herford - Nordrhein-Westfalen)": "057580000000", + "Spenge, Stadt (Herford - Nordrhein-Westfalen)": "057580000000", + "Vlotho, Stadt (Herford - Nordrhein-Westfalen)": "057580000000", + "Bad Driburg, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Beverungen, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Borgentreich, Orgelstadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Brakel, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Höxter, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Marienmünster, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Nieheim, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Steinheim, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Warburg, Hansestadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Willebadessen, Stadt (Höxter - Nordrhein-Westfalen)": "057620000000", + "Augustdorf (Lippe - Nordrhein-Westfalen)": "057660000000", + "Bad Salzuflen, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Barntrup, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Blomberg, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Detmold, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Dörentrup (Lippe - Nordrhein-Westfalen)": "057660000000", + "Extertal (Lippe - Nordrhein-Westfalen)": "057660000000", + "Horn-Bad Meinberg, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Kalletal (Lippe - Nordrhein-Westfalen)": "057660000000", + "Lage, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Lemgo, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Leopoldshöhe (Lippe - Nordrhein-Westfalen)": "057660000000", + "Lügde, Stadt der Osterräder (Lippe - Nordrhein-Westfalen)": "057660000000", + "Oerlinghausen, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Schieder-Schwalenberg, Stadt (Lippe - Nordrhein-Westfalen)": "057660000000", + "Schlangen (Lippe - Nordrhein-Westfalen)": "057660000000", + "Bad Oeynhausen, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Espelkamp, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Hille (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Hüllhorst (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Lübbecke, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Minden, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Petershagen, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Porta Westfalica, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Preußisch Oldendorf, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Rahden, Stadt (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Stemwede (Minden-Lübbecke - Nordrhein-Westfalen)": "057700000000", + "Altenbeken (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Bad Lippspringe, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Borchen (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Büren, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Delbrück, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Hövelhof, Sennegemeinde (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Lichtenau, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Paderborn, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Salzkotten, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Bad Wünnenberg, Stadt (Paderborn - Nordrhein-Westfalen)": "057740000000", + "Bochum, Stadt": "059110000000", + "Dortmund, Stadt": "059130000000", + "Hagen, Stadt der FernUniversität": "059140000000", + "Hamm, Stadt": "059150000000", + "Herne, Stadt": "059160000000", + "Breckerfeld, Hansestadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Ennepetal, Stadt der Kluterthöhle (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Gevelsberg, Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Hattingen, Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Herdecke, Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Schwelm, Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Sprockhövel, Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Wetter (Ruhr), Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Witten, Stadt (Ennepe-Ruhr-Kreis - Nordrhein-Westfalen)": "059540000000", + "Arnsberg, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Bestwig (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Brilon, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Eslohe (Sauerland) (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Hallenberg, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Marsberg, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Medebach, Hansestadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Meschede, Kreis- und Hochschulstadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Olsberg, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Schmallenberg, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Sundern (Sauerland), Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Winterberg, Stadt (Hochsauerlandkreis - Nordrhein-Westfalen)": "059580000000", + "Altena, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Balve, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Halver, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Hemer, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Herscheid (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Iserlohn, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Kierspe, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Lüdenscheid, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Meinerzhagen, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Menden (Sauerland), Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Nachrodt-Wiblingwerde (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Neuenrade, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Plettenberg, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Schalksmühle (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Werdohl, Stadt (Märkischer Kreis - Nordrhein-Westfalen)": "059620000000", + "Attendorn, Hansestadt (Olpe - Nordrhein-Westfalen)": "059660000000", + "Drolshagen, Stadt (Olpe - Nordrhein-Westfalen)": "059660000000", + "Finnentrop (Olpe - Nordrhein-Westfalen)": "059660000000", + "Kirchhundem (Olpe - Nordrhein-Westfalen)": "059660000000", + "Lennestadt, Stadt (Olpe - Nordrhein-Westfalen)": "059660000000", + "Olpe, Stadt (Olpe - Nordrhein-Westfalen)": "059660000000", + "Wenden (Olpe - Nordrhein-Westfalen)": "059660000000", + "Bad Berleburg, Stadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Burbach (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Erndtebrück (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Freudenberg, Stadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Hilchenbach, Stadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Kreuztal, Stadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Bad Laasphe, Stadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Netphen, Stadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Neunkirchen (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Siegen, Universitätsstadt (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Wilnsdorf (Siegen-Wittgenstein - Nordrhein-Westfalen)": "059700000000", + "Anröchte (Soest - Nordrhein-Westfalen)": "059740000000", + "Bad Sassendorf (Soest - Nordrhein-Westfalen)": "059740000000", + "Ense (Soest - Nordrhein-Westfalen)": "059740000000", + "Erwitte, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Geseke, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Lippetal (Soest - Nordrhein-Westfalen)": "059740000000", + "Lippstadt, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Möhnesee (Soest - Nordrhein-Westfalen)": "059740000000", + "Rüthen, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Soest, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Warstein, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Welver (Soest - Nordrhein-Westfalen)": "059740000000", + "Werl, Stadt (Soest - Nordrhein-Westfalen)": "059740000000", + "Wickede (Ruhr) (Soest - Nordrhein-Westfalen)": "059740000000", + "Bergkamen, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Bönen (Unna - Nordrhein-Westfalen)": "059780000000", + "Fröndenberg/Ruhr, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Holzwickede (Unna - Nordrhein-Westfalen)": "059780000000", + "Kamen, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Lünen, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Schwerte, Hansestadt an der Ruhr (Unna - Nordrhein-Westfalen)": "059780000000", + "Selm, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Unna, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Werne, Stadt (Unna - Nordrhein-Westfalen)": "059780000000", + "Darmstadt, Wissenschaftsstadt": "064110000000", + "Frankfurt am Main, Stadt": "064120000000", + "Offenbach am Main, Stadt": "064130000000", + "Wiesbaden, Landeshauptstadt": "064140000000", + "Abtsteinach (Bergstraße - Hessen)": "064310000000", + "Bensheim, Stadt (Bergstraße - Hessen)": "064310000000", + "Biblis (Bergstraße - Hessen)": "064310000000", + "Birkenau (Bergstraße - Hessen)": "064310000000", + "Bürstadt, Stadt (Bergstraße - Hessen)": "064310000000", + "Einhausen (Bergstraße - Hessen)": "064310000000", + "Fürth (Bergstraße - Hessen)": "064310000000", + "Gorxheimertal (Bergstraße - Hessen)": "064310000000", + "Grasellenbach (Bergstraße - Hessen)": "064310000000", + "Groß-Rohrheim (Bergstraße - Hessen)": "064310000000", + "Heppenheim (Bergstraße), Kreisstadt (Bergstraße - Hessen)": "064310000000", + "Hirschhorn (Neckar), Stadt (Bergstraße - Hessen)": "064310000000", + "Lampertheim, Stadt (Bergstraße - Hessen)": "064310000000", + "Lautertal (Odenwald) (Bergstraße - Hessen)": "064310000000", + "Lindenfels, Stadt (Bergstraße - Hessen)": "064310000000", + "Lorsch, Karolingerstadt (Bergstraße - Hessen)": "064310000000", + "Mörlenbach (Bergstraße - Hessen)": "064310000000", + "Neckarsteinach, Stadt (Bergstraße - Hessen)": "064310000000", + "Rimbach (Bergstraße - Hessen)": "064310000000", + "Viernheim, Stadt (Bergstraße - Hessen)": "064310000000", + "Wald-Michelbach (Bergstraße - Hessen)": "064310000000", + "Zwingenberg, Stadt (Bergstraße - Hessen)": "064310000000", + "Michelbuch, gemfr. Gebiet (Bergstraße - Hessen)": "064310000000", + "Alsbach-Hähnlein (Darmstadt-Dieburg - Hessen)": "064320000000", + "Babenhausen, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Bickenbach (Darmstadt-Dieburg - Hessen)": "064320000000", + "Dieburg, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Eppertshausen (Darmstadt-Dieburg - Hessen)": "064320000000", + "Erzhausen (Darmstadt-Dieburg - Hessen)": "064320000000", + "Fischbachtal (Darmstadt-Dieburg - Hessen)": "064320000000", + "Griesheim, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Groß-Bieberau, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Groß-Umstadt, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Groß-Zimmern (Darmstadt-Dieburg - Hessen)": "064320000000", + "Messel (Darmstadt-Dieburg - Hessen)": "064320000000", + "Modautal (Darmstadt-Dieburg - Hessen)": "064320000000", + "Mühltal (Darmstadt-Dieburg - Hessen)": "064320000000", + "Münster (Hessen) (Darmstadt-Dieburg - Hessen)": "064320000000", + "Ober-Ramstadt, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Otzberg (Darmstadt-Dieburg - Hessen)": "064320000000", + "Pfungstadt, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Reinheim, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Roßdorf (Darmstadt-Dieburg - Hessen)": "064320000000", + "Schaafheim (Darmstadt-Dieburg - Hessen)": "064320000000", + "Seeheim-Jugenheim (Darmstadt-Dieburg - Hessen)": "064320000000", + "Weiterstadt, Stadt (Darmstadt-Dieburg - Hessen)": "064320000000", + "Biebesheim am Rhein (Groß-Gerau - Hessen)": "064330000000", + "Bischofsheim (Groß-Gerau - Hessen)": "064330000000", + "Büttelborn (Groß-Gerau - Hessen)": "064330000000", + "Gernsheim, Schöfferstadt (Groß-Gerau - Hessen)": "064330000000", + "Ginsheim-Gustavsburg, Stadt (Groß-Gerau - Hessen)": "064330000000", + "Groß-Gerau, Stadt (Groß-Gerau - Hessen)": "064330000000", + "Kelsterbach, Stadt (Groß-Gerau - Hessen)": "064330000000", + "Mörfelden-Walldorf, Stadt (Groß-Gerau - Hessen)": "064330000000", + "Nauheim (Groß-Gerau - Hessen)": "064330000000", + "Raunheim, Stadt (Groß-Gerau - Hessen)": "064330000000", + "Riedstadt, Büchnerstadt (Groß-Gerau - Hessen)": "064330000000", + "Rüsselsheim am Main, Stadt (Groß-Gerau - Hessen)": "064330000000", + "Stockstadt am Rhein (Groß-Gerau - Hessen)": "064330000000", + "Trebur (Groß-Gerau - Hessen)": "064330000000", + "Bad Homburg v. d. Höhe, Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Friedrichsdorf, Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Glashütten (Hochtaunuskreis - Hessen)": "064340000000", + "Grävenwiesbach (Hochtaunuskreis - Hessen)": "064340000000", + "Königstein im Taunus, Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Kronberg im Taunus, Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Neu-Anspach, Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Oberursel (Taunus), Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Schmitten (Hochtaunuskreis - Hessen)": "064340000000", + "Steinbach (Taunus), Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Usingen, Stadt (Hochtaunuskreis - Hessen)": "064340000000", + "Wehrheim (Hochtaunuskreis - Hessen)": "064340000000", + "Weilrod (Hochtaunuskreis - Hessen)": "064340000000", + "Bad Orb, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Bad Soden-Salmünster, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Biebergemünd (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Birstein (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Brachttal (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Bruchköbel, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Erlensee, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Flörsbachtal (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Freigericht (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Gelnhausen, Barbarossast., Krst. (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Großkrotzenburg (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Gründau (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Hammersbach (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Hanau, Brüder-Grimm-Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Hasselroth (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Jossgrund (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Langenselbold, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Linsengericht (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Maintal, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Neuberg (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Nidderau, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Niederdorfelden (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Rodenbach (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Ronneburg (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Schlüchtern, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Schöneck (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Sinntal (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Steinau an der Straße, Brüder-Grimm-Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Wächtersbach, Stadt (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Gutsbezirk Spessart, gemfr. Gebiet (Main-Kinzig-Kreis - Hessen)": "064350000000", + "Bad Soden am Taunus, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Eppstein, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Eschborn, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Flörsheim am Main, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Hattersheim am Main, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Hochheim am Main, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Hofheim am Taunus, Kreisstadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Kelkheim (Taunus), Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Kriftel (Main-Taunus-Kreis - Hessen)": "064360000000", + "Liederbach am Taunus (Main-Taunus-Kreis - Hessen)": "064360000000", + "Schwalbach am Taunus, Stadt (Main-Taunus-Kreis - Hessen)": "064360000000", + "Sulzbach (Taunus) (Main-Taunus-Kreis - Hessen)": "064360000000", + "Bad König, Stadt (Odenwaldkreis - Hessen)": "064370000000", + "Brensbach (Odenwaldkreis - Hessen)": "064370000000", + "Breuberg, Stadt (Odenwaldkreis - Hessen)": "064370000000", + "Brombachtal (Odenwaldkreis - Hessen)": "064370000000", + "Erbach, Kreisstadt (Odenwaldkreis - Hessen)": "064370000000", + "Fränkisch-Crumbach (Odenwaldkreis - Hessen)": "064370000000", + "Höchst i. Odw. (Odenwaldkreis - Hessen)": "064370000000", + "Lützelbach (Odenwaldkreis - Hessen)": "064370000000", + "Michelstadt, Stadt (Odenwaldkreis - Hessen)": "064370000000", + "Mossautal (Odenwaldkreis - Hessen)": "064370000000", + "Reichelsheim (Odenwald) (Odenwaldkreis - Hessen)": "064370000000", + "Oberzent, Stadt (Odenwaldkreis - Hessen)": "064370000000", + "Dietzenbach, Kreisstadt (Offenbach - Hessen)": "064380000000", + "Dreieich, Stadt (Offenbach - Hessen)": "064380000000", + "Egelsbach (Offenbach - Hessen)": "064380000000", + "Hainburg (Offenbach - Hessen)": "064380000000", + "Heusenstamm, Stadt (Offenbach - Hessen)": "064380000000", + "Langen (Hessen), Stadt (Offenbach - Hessen)": "064380000000", + "Mainhausen (Offenbach - Hessen)": "064380000000", + "Mühlheim am Main, Stadt (Offenbach - Hessen)": "064380000000", + "Neu-Isenburg, Stadt (Offenbach - Hessen)": "064380000000", + "Obertshausen, Stadt (Offenbach - Hessen)": "064380000000", + "Rodgau, Stadt (Offenbach - Hessen)": "064380000000", + "Rödermark, Stadt (Offenbach - Hessen)": "064380000000", + "Seligenstadt, Einhardstadt (Offenbach - Hessen)": "064380000000", + "Aarbergen (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Bad Schwalbach, Kreisstadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Eltville am Rhein, Stadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Geisenheim, Hochschulstadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Heidenrod (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Hohenstein (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Hünstetten (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Idstein, Hochschulstadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Kiedrich (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Lorch, Stadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Niedernhausen (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Oestrich-Winkel, Stadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Rüdesheim am Rhein, Stadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Schlangenbad (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Taunusstein, Stadt (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Waldems (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Walluf (Rheingau-Taunus-Kreis - Hessen)": "064390000000", + "Altenstadt (Wetteraukreis - Hessen)": "064400000000", + "Bad Nauheim, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Bad Vilbel, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Büdingen, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Butzbach, Friedrich-Ludwig-Weidig-Stadt (Wetteraukreis - Hessen)": "064400000000", + "Echzell (Wetteraukreis - Hessen)": "064400000000", + "Florstadt, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Friedberg (Hessen), Kreisstadt (Wetteraukreis - Hessen)": "064400000000", + "Gedern, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Glauburg (Wetteraukreis - Hessen)": "064400000000", + "Hirzenhain (Wetteraukreis - Hessen)": "064400000000", + "Karben, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Kefenrod (Wetteraukreis - Hessen)": "064400000000", + "Limeshain (Wetteraukreis - Hessen)": "064400000000", + "Münzenberg, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Nidda, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Niddatal, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Ober-Mörlen (Wetteraukreis - Hessen)": "064400000000", + "Ortenberg, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Ranstadt (Wetteraukreis - Hessen)": "064400000000", + "Reichelsheim (Wetterau), Stadt (Wetteraukreis - Hessen)": "064400000000", + "Rockenberg (Wetteraukreis - Hessen)": "064400000000", + "Rosbach v. d. Höhe, Stadt (Wetteraukreis - Hessen)": "064400000000", + "Wölfersheim (Wetteraukreis - Hessen)": "064400000000", + "Wöllstadt (Wetteraukreis - Hessen)": "064400000000", + "Allendorf (Lumda), Stadt (Gießen - Hessen)": "065310000000", + "Biebertal (Gießen - Hessen)": "065310000000", + "Buseck (Gießen - Hessen)": "065310000000", + "Fernwald (Gießen - Hessen)": "065310000000", + "Gießen, Universitätsstadt (Gießen - Hessen)": "065310000000", + "Grünberg, Stadt (Gießen - Hessen)": "065310000000", + "Heuchelheim a. d. Lahn (Gießen - Hessen)": "065310000000", + "Hungen, Stadt (Gießen - Hessen)": "065310000000", + "Langgöns (Gießen - Hessen)": "065310000000", + "Laubach, Stadt (Gießen - Hessen)": "065310000000", + "Lich, Stadt (Gießen - Hessen)": "065310000000", + "Linden, Stadt (Gießen - Hessen)": "065310000000", + "Lollar, Stadt (Gießen - Hessen)": "065310000000", + "Pohlheim, Stadt (Gießen - Hessen)": "065310000000", + "Rabenau (Gießen - Hessen)": "065310000000", + "Reiskirchen (Gießen - Hessen)": "065310000000", + "Staufenberg, Stadt (Gießen - Hessen)": "065310000000", + "Wettenberg (Gießen - Hessen)": "065310000000", + "Aßlar, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Bischoffen (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Braunfels, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Breitscheid (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Dietzhölztal (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Dillenburg, Oranienstadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Driedorf (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Ehringshausen (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Eschenburg (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Greifenstein (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Haiger, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Herborn, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Hohenahr (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Hüttenberg (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Lahnau (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Leun, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Mittenaar (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Schöffengrund (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Siegbach (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Sinn (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Solms, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Waldsolms (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Wetzlar, Stadt (Lahn-Dill-Kreis - Hessen)": "065320000000", + "Beselich (Limburg-Weilburg - Hessen)": "065330000000", + "Brechen (Limburg-Weilburg - Hessen)": "065330000000", + "Bad Camberg, Stadt (Limburg-Weilburg - Hessen)": "065330000000", + "Dornburg (Limburg-Weilburg - Hessen)": "065330000000", + "Elbtal (Limburg-Weilburg - Hessen)": "065330000000", + "Elz (Limburg-Weilburg - Hessen)": "065330000000", + "Hadamar, Stadt (Limburg-Weilburg - Hessen)": "065330000000", + "Hünfelden (Limburg-Weilburg - Hessen)": "065330000000", + "Limburg a. d. Lahn, Kreisstadt (Limburg-Weilburg - Hessen)": "065330000000", + "Löhnberg (Limburg-Weilburg - Hessen)": "065330000000", + "Mengerskirchen, Marktflecken (Limburg-Weilburg - Hessen)": "065330000000", + "Merenberg, Marktflecken (Limburg-Weilburg - Hessen)": "065330000000", + "Runkel, Stadt (Limburg-Weilburg - Hessen)": "065330000000", + "Selters (Taunus) (Limburg-Weilburg - Hessen)": "065330000000", + "Villmar, Marktflecken (Limburg-Weilburg - Hessen)": "065330000000", + "Waldbrunn (Westerwald) (Limburg-Weilburg - Hessen)": "065330000000", + "Weilburg, Stadt (Limburg-Weilburg - Hessen)": "065330000000", + "Weilmünster, Marktflecken (Limburg-Weilburg - Hessen)": "065330000000", + "Weinbach (Limburg-Weilburg - Hessen)": "065330000000", + "Amöneburg, Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Angelburg (Marburg-Biedenkopf - Hessen)": "065340000000", + "Bad Endbach (Marburg-Biedenkopf - Hessen)": "065340000000", + "Biedenkopf, Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Breidenbach (Marburg-Biedenkopf - Hessen)": "065340000000", + "Cölbe (Marburg-Biedenkopf - Hessen)": "065340000000", + "Dautphetal (Marburg-Biedenkopf - Hessen)": "065340000000", + "Ebsdorfergrund (Marburg-Biedenkopf - Hessen)": "065340000000", + "Fronhausen (Marburg-Biedenkopf - Hessen)": "065340000000", + "Gladenbach, Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Kirchhain, Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Lahntal (Marburg-Biedenkopf - Hessen)": "065340000000", + "Lohra (Marburg-Biedenkopf - Hessen)": "065340000000", + "Marburg, Universitätsstadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Münchhausen (Marburg-Biedenkopf - Hessen)": "065340000000", + "Neustadt (Hessen), Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Rauschenberg, Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Stadtallendorf, Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Steffenberg (Marburg-Biedenkopf - Hessen)": "065340000000", + "Weimar (Lahn) (Marburg-Biedenkopf - Hessen)": "065340000000", + "Wetter (Hessen), Stadt (Marburg-Biedenkopf - Hessen)": "065340000000", + "Wohratal (Marburg-Biedenkopf - Hessen)": "065340000000", + "Alsfeld, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Antrifttal (Vogelsbergkreis - Hessen)": "065350000000", + "Feldatal (Vogelsbergkreis - Hessen)": "065350000000", + "Freiensteinau (Vogelsbergkreis - Hessen)": "065350000000", + "Gemünden (Felda) (Vogelsbergkreis - Hessen)": "065350000000", + "Grebenau, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Grebenhain (Vogelsbergkreis - Hessen)": "065350000000", + "Herbstein, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Homberg (Ohm), Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Kirtorf, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Lauterbach (Hessen), Kreisstadt (Vogelsbergkreis - Hessen)": "065350000000", + "Lautertal (Vogelsberg) (Vogelsbergkreis - Hessen)": "065350000000", + "Mücke (Vogelsbergkreis - Hessen)": "065350000000", + "Romrod, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Schlitz, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Schotten, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Schwalmtal (Vogelsbergkreis - Hessen)": "065350000000", + "Ulrichstein, Stadt (Vogelsbergkreis - Hessen)": "065350000000", + "Wartenberg (Vogelsbergkreis - Hessen)": "065350000000", + "Kassel, documenta-Stadt": "066110000000", + "Bad Salzschlirf (Fulda - Hessen)": "066310000000", + "Burghaun, Marktgemeinde (Fulda - Hessen)": "066310000000", + "Dipperz (Fulda - Hessen)": "066310000000", + "Ebersburg (Fulda - Hessen)": "066310000000", + "Ehrenberg (Rhön) (Fulda - Hessen)": "066310000000", + "Eichenzell (Fulda - Hessen)": "066310000000", + "Eiterfeld, Marktgemeinde (Fulda - Hessen)": "066310000000", + "Flieden (Fulda - Hessen)": "066310000000", + "Fulda, Stadt (Fulda - Hessen)": "066310000000", + "Gersfeld (Rhön), Stadt (Fulda - Hessen)": "066310000000", + "Großenlüder (Fulda - Hessen)": "066310000000", + "Hilders, Marktgemeinde (Fulda - Hessen)": "066310000000", + "Hofbieber (Fulda - Hessen)": "066310000000", + "Hosenfeld (Fulda - Hessen)": "066310000000", + "Hünfeld, Konrad-Zuse-Stadt (Fulda - Hessen)": "066310000000", + "Kalbach (Fulda - Hessen)": "066310000000", + "Künzell (Fulda - Hessen)": "066310000000", + "Neuhof (Fulda - Hessen)": "066310000000", + "Nüsttal (Fulda - Hessen)": "066310000000", + "Petersberg (Fulda - Hessen)": "066310000000", + "Poppenhausen (Wasserkuppe) (Fulda - Hessen)": "066310000000", + "Rasdorf, Point-Alpha-Gemeinde (Fulda - Hessen)": "066310000000", + "Tann (Rhön), Stadt (Fulda - Hessen)": "066310000000", + "Alheim (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Bad Hersfeld, Kreisstadt (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Bebra, Stadt (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Breitenbach a. Herzberg (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Cornberg (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Friedewald (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Hauneck (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Haunetal (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Heringen (Werra), Stadt (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Hohenroda (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Kirchheim (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Ludwigsau (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Nentershausen (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Neuenstein (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Niederaula, Marktgemeinde (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Philippsthal (Werra), Marktgemeinde (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Ronshausen (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Rotenburg a. d. Fulda, Stadt (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Schenklengsfeld (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Wildeck (Hersfeld-Rotenburg - Hessen)": "066320000000", + "Ahnatal (Kassel - Hessen)": "066330000000", + "Bad Karlshafen, Stadt (Kassel - Hessen)": "066330000000", + "Baunatal, Stadt (Kassel - Hessen)": "066330000000", + "Breuna (Kassel - Hessen)": "066330000000", + "Calden (Kassel - Hessen)": "066330000000", + "Bad Emstal (Kassel - Hessen)": "066330000000", + "Espenau (Kassel - Hessen)": "066330000000", + "Fuldabrück (Kassel - Hessen)": "066330000000", + "Fuldatal (Kassel - Hessen)": "066330000000", + "Grebenstein, Stadt (Kassel - Hessen)": "066330000000", + "Habichtswald (Kassel - Hessen)": "066330000000", + "Helsa (Kassel - Hessen)": "066330000000", + "Hofgeismar, Stadt (Kassel - Hessen)": "066330000000", + "Immenhausen, Stadt (Kassel - Hessen)": "066330000000", + "Kaufungen (Kassel - Hessen)": "066330000000", + "Liebenau, Stadt (Kassel - Hessen)": "066330000000", + "Lohfelden (Kassel - Hessen)": "066330000000", + "Naumburg, Stadt (Kassel - Hessen)": "066330000000", + "Nieste (Kassel - Hessen)": "066330000000", + "Niestetal (Kassel - Hessen)": "066330000000", + "Reinhardshagen (Kassel - Hessen)": "066330000000", + "Schauenburg (Kassel - Hessen)": "066330000000", + "Söhrewald (Kassel - Hessen)": "066330000000", + "Trendelburg, Stadt (Kassel - Hessen)": "066330000000", + "Vellmar, Stadt (Kassel - Hessen)": "066330000000", + "Wolfhagen, Hans-Staden-Stadt (Kassel - Hessen)": "066330000000", + "Zierenberg, Stadt (Kassel - Hessen)": "066330000000", + "Wesertal (Kassel - Hessen)": "066330000000", + "Gutsbezirk Reinhardswald, gemfr. Gebiet (Kassel - Hessen)": "066330000000", + "Borken (Hessen), Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Edermünde (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Felsberg, Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Frielendorf, Marktflecken (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Fritzlar, Dom- und Kaiserstadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Gilserberg (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Gudensberg, Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Guxhagen (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Homberg (Efze), Reformationsstadt, Kreisstadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Jesberg (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Knüllwald (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Körle (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Malsfeld (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Melsungen, Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Morschen (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Neuental (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Neukirchen, Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Niedenstein, Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Oberaula (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Ottrau (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Schrecksbach (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Schwalmstadt, Konfirmationsstadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Schwarzenborn, Stadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Spangenberg, Liebenbachstadt (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Wabern (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Willingshausen (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Bad Zwesten (Schwalm-Eder-Kreis - Hessen)": "066340000000", + "Allendorf (Eder) (Waldeck-Frankenberg - Hessen)": "066350000000", + "Bad Arolsen, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Bad Wildungen, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Battenberg (Eder), Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Bromskirchen (Waldeck-Frankenberg - Hessen)": "066350000000", + "Burgwald (Waldeck-Frankenberg - Hessen)": "066350000000", + "Diemelsee (Waldeck-Frankenberg - Hessen)": "066350000000", + "Diemelstadt, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Edertal, Nationalparkgemeinde (Waldeck-Frankenberg - Hessen)": "066350000000", + "Frankenau, Nationalparkstadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Frankenberg (Eder), Philipp-Soldan-Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Gemünden (Wohra), Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Haina (Kloster) (Waldeck-Frankenberg - Hessen)": "066350000000", + "Hatzfeld (Eder), Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Korbach, Hansestadt, Kreisstadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Lichtenfels, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Rosenthal, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Twistetal (Waldeck-Frankenberg - Hessen)": "066350000000", + "Vöhl, Nationalparkgemeinde (Waldeck-Frankenberg - Hessen)": "066350000000", + "Volkmarsen, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Waldeck, Stadt (Waldeck-Frankenberg - Hessen)": "066350000000", + "Willingen (Upland) (Waldeck-Frankenberg - Hessen)": "066350000000", + "Bad Sooden-Allendorf, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Berkatal (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Eschwege, Kreisstadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Großalmerode, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Herleshausen (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Hessisch Lichtenau, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Meinhard (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Meißner (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Neu-Eichenberg (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Ringgau (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Sontra, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Waldkappel, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Wanfried, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Wehretal (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Weißenborn (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Witzenhausen, Stadt (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Gutsbezirk Kaufunger Wald, gemfr. Gebiet (Werra-Meißner-Kreis - Hessen)": "066360000000", + "Gemeinsames deutsch-luxemburgisches Hoheitsgebiet": "070000000000", + "Koblenz, Stadt": "071110000000", + "Bad Neuenahr-Ahrweiler, Stadt (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Remagen, Stadt (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Sinzig, Stadt (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Grafschaft (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Adenau, Stadt (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Antweiler (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Aremberg (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Barweiler (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Bauler (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Dankerath (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Dorsel (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Eichenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Fuchshofen (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Harscheid (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Herschbroich (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Hoffeld (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Honerath (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Hümmel (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Insul (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Kaltenborn (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Kottenborn (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Leimbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Meuspath (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Müllenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Müsch (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Nürburg (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Ohlenhard (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Pomster (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Quiddelbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Reifferscheid (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Rodder (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Schuld (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Senscheid (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Sierscheid (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Trierscheid (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Wershofen (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Wiesemscheid (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Wimbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Winnerath (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Wirft (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Dümpelfeld (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Ahrbrück (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Altenahr (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Berg (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Dernau (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Heckenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Hönningen (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Kalenborn (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Kesseling (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Kirchsahr (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Lind (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Mayschoß (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Rech (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Bad Breisig, Stadt (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Brohl-Lützing (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Gönnersdorf (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Waldorf (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Dedenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Königsfeld (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Niederdürenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Niederzissen (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Oberdürenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Oberzissen (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Schalkenbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Brenk (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Burgbrohl (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Galenberg (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Glees (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Hohenleimbach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Spessart (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Wassenach (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Wehr (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Weibern (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Kempenich (Ahrweiler - Rheinland-Pfalz)": "071310000000", + "Daaden, Stadt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Derschen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Emmerzhausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Friedewald (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Herdorf, Stadt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Mauden (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Niederdreisbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Nisterberg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Schutzbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Weitefeld (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Birkenbeul (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Bitzen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Breitscheidt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Bruchertseifen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Etzbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Forst (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Fürthen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Hamm (Sieg) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Niederirsen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Pracht (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Roth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Seelbach bei Hamm (Sieg) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Brachbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Friesenhagen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Harbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Kirchen (Sieg), Stadt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Mudersbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Niederfischbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Birken-Honigsessen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Mittelhof (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Hövels (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Katzwinkel (Sieg) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Selbach (Sieg) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Wissen, Stadt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Alsdorf (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Betzdorf, Stadt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Dickendorf (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Elben (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Elkenroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Fensdorf (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Gebhardshain (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Grünebach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Kausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Malberg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Molzhain (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Nauroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Rosenheim (Landkreis Altenkirchen) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Scheuerfeld (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Steinebach/ Sieg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Steineroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Wallmenroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Almersbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Bachenberg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Berzhausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Birnbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Bürdenbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Burglahr (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Busenhausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Eichelhardt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Eichen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Ersfeld (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Eulenberg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Fiersbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Flammersfeld (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Fluterschen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Forstmehren (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Gieleroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Giershausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Güllesheim (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Hasselbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Helmenzen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Helmeroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Hemmelzen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Heupelzen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Hilgenroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Hirz-Maulsbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Horhausen (Westerwald) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Idelberg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Ingelbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Isert (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Kescheid (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Kettenhausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Kircheib (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Kraam (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Krunkel (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Mammelzen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Mehren (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Michelbach (Westerwald) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Niedersteinebach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Obererbach (Westerwald) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Oberirsen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Oberlahr (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Obersteinebach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Oberwambach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Ölsen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Orfgen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Peterslahr (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Pleckhausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Racksen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Reiferscheid (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Rettersen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Rott (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Schöneberg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Schürdt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Seelbach (Westerwald) (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Seifen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Sörth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Stürzelbach (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Volkerzen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Walterschen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Werkhausen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Weyerbusch (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Willroth (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Wölmersen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Ziegenhain (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Berod bei Hachenburg (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Altenkirchen (Westerwald), Stadt (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Neitersen (Altenkirchen (Westerwald) - Rheinland-Pfalz)": "071320000000", + "Bad Kreuznach, Stadt (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Altenbamberg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Biebelsheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Feilbingert (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Frei-Laubersheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Fürfeld (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hackenheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hallgarten (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hochstätten (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Neu-Bamberg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Pfaffen-Schwabenheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Pleitersheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Tiefenthal (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Volxheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Allenfeld (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Argenschwang (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Bockenau (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Boos (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Braunweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Burgsponheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Dalberg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Duchroth (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Gebroth (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Gutenberg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hargesheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hergenfeld (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hüffelsheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Mandel (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Münchwald (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Niederhausen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Norheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Oberhausen an der Nahe (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Oberstreit (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Roxheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Sankt Katharinen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schloßböckelheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Sommerloch (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Spabrücken (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Spall (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Sponheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Traisen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Waldböckelheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Wallhausen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Weinsheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Winterbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Rüdesheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Bärenbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Becherbach bei Kirn (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Brauweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hahnenbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Heimweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Heinzenberg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hennweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hochstetten-Dhaun (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Horbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Kirn, Stadt (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Limbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Meckenbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Oberhausen bei Kirn (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Otzweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Simmertal (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Weitersborn (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Bruschied (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Kellenbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Königsau (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schneppenbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schwarzerden (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Abtweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Auen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Bärweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Becherbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Breitenheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Callbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Daubach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Desloch (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Hundsbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Ippenschied (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Jeckenbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Kirschroth (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Langenthal (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Lauschied (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Lettweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Löllbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Martinstein (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Meddersheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Meisenheim, Stadt (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Merxheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Monzingen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Nußbaum (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Odernheim am Glan (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Raumbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Rehbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Rehborn (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Reiffelbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schmittweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schweinschied (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Seesbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Staudernheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Weiler bei Monzingen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Winterburg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Bad Sobernheim, Stadt (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Bretzenheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Daxweiler (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Dörrebach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Dorsheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Eckenroth (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Guldental (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Langenlonsheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Laubenheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Roth (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Rümmelsheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schöneberg (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Schweppenhausen (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Seibersbach (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Stromberg, Stadt (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Waldlaubersheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Warmsroth (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Windesheim (Bad Kreuznach - Rheinland-Pfalz)": "071330000000", + "Idar-Oberstein, Stadt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Baumholder, Stadt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Berglangenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Berschweiler bei Baumholder (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Eckersweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Fohren-Linden (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Frauenberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hahnweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Heimbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Leitzweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Mettweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Reichenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Rohrbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Rückweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Ruschberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Abentheuer (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Achtelsbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Birkenfeld, Stadt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Börfink (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Brücken (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Buhlenberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Dambach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Dienstweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Elchweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Ellenberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Ellweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Gimbweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Gollenberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hattgenstein (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hoppstädten-Weiersbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Kronweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Leisel (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Meckenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Niederbrombach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Niederhambach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Nohen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Oberbrombach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Oberhambach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Rimsberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Rinzenberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Rötsweiler-Nockenthal (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Schmißberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Schwollen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Siesbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Sonnenberg-Winnenberg (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Wilzenberg-Hußweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Allenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Asbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Bergen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Berschweiler bei Kirn (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Bollenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Breitenthal (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Bruchweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Bundenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Dickesbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Fischbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Gerach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Gösenroth (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Griebelschied (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hausen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hellertshausen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Herborn (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Herrstein (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hettenrodt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hintertiefenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Horbruch (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Hottenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Kempfeld (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Kirschweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Krummenau (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Mackenrodt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Mittelreidenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Mörschied (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Niederhosenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Niederwörresbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Oberhosenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Oberkirn (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Oberreidenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Oberwörresbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Rhaunen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Schauren (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Schmidthachenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Schwerbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Sensweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Sien (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Sienhachenbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Sonnschied (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Stipshausen (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Sulzbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Veitsrodt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Vollmersbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Weiden (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Weitersbach (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Wickenrodt (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Wirschweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Langweiler (Birkenfeld - Rheinland-Pfalz)": "071340000000", + "Beilstein (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Bremm (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Briedern (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Bruttig-Fankel (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Cochem, Stadt (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Dohr (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Ediger-Eller (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Ellenz-Poltersdorf (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Ernst (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Faid (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Greimersburg (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Klotten (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Lieg (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Lütz (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Mesenich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Moselkern (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Müden (Mosel) (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Nehren (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Pommern (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Senheim (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Treis-Karden (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Valwig (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Wirfus (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Binningen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Brachtendorf (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Brieden (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Brohl (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Dünfus (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Düngenheim (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Eppenberg (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Eulgem (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Forst (Eifel) (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Gamlen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Hambuch (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Hauroth (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Illerich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Kaifenheim (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Kail (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Kaisersesch, Stadt (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Kalenborn (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Landkern (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Laubach (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Masburg (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Möntenich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Müllenbach (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Roes (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Urmersbach (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Zettingen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Leienkaul (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Alflen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Auderath (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Beuren (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Büchel (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Filz (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Gevenich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Gillenbeuren (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Kliding (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Lutzerath (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Schmitt (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Ulmen, Stadt (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Urschmitt (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Wagenhausen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Weiler (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Wollmerath (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Bad Bertrich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Alf (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Altlay (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Altstrimmig (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Blankenrath (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Briedel (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Bullay (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Forst (Hunsrück) (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Grenderich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Haserich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Hesweiler (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Liesenich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Mittelstrimmig (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Moritzheim (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Neef (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Panzweiler (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Peterswald-Löffelscheid (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Pünderich (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Reidenhausen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Sankt Aldegund (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Schauren (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Sosberg (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Tellig (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Walhausen (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Zell (Mosel), Stadt (Cochem-Zell - Rheinland-Pfalz)": "071350000000", + "Andernach, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Mayen, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Bendorf, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kretz (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kruft (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Nickenich (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Plaidt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Saffig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Einig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Gappenach (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Gering (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Gierschnach (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kalt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kerben (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kollig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Lonnig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Mertloch (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Naunheim (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Ochtendung (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Pillig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Polch, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Rüber (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Trimbs (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Welling (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Wierschem (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Münstermaifeld, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Acht (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Anschau (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Arft (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Baar (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Bermel (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Boos (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Ditscheid (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Ettringen (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Hausten (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Herresbach (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Hirten (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kehrig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kirchwald (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kottenheim (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Langenfeld (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Langscheid (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Lind (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Luxem (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Monreal (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Münk (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Nachtsheim (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Reudelsterz (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Sankt Johann (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Siebenbach (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Virneburg (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Weiler (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Welschenbach (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Bell (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Mendig, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Rieden (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Thür (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Volkesfeld (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Niederwerth (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Urbar (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Vallendar, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Weitersburg (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Bassenheim (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kaltenengers (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kettig (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Mülheim-Kärlich, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Sankt Sebastian (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Urmitz (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Weißenthurm, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Alken (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Brey (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Brodenbach (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Burgen (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Dieblich (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Hatzenport (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Kobern-Gondorf (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Löf (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Macken (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Niederfell (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Nörtershausen (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Oberfell (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Rhens, Stadt (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Spay (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Waldesch (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Winningen (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Wolken (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Lehmen (Mayen-Koblenz - Rheinland-Pfalz)": "071370000000", + "Neuwied, Stadt (Neuwied - Rheinland-Pfalz)": "071380000000", + "Asbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Neustadt (Wied) (Neuwied - Rheinland-Pfalz)": "071380000000", + "Windhagen (Neuwied - Rheinland-Pfalz)": "071380000000", + "Buchholz (Westerwald) (Neuwied - Rheinland-Pfalz)": "071380000000", + "Bad Hönningen, Stadt (Neuwied - Rheinland-Pfalz)": "071380000000", + "Hammerstein (Neuwied - Rheinland-Pfalz)": "071380000000", + "Leutesdorf (Neuwied - Rheinland-Pfalz)": "071380000000", + "Rheinbrohl (Neuwied - Rheinland-Pfalz)": "071380000000", + "Dierdorf, Stadt (Neuwied - Rheinland-Pfalz)": "071380000000", + "Großmaischeid (Neuwied - Rheinland-Pfalz)": "071380000000", + "Isenburg (Neuwied - Rheinland-Pfalz)": "071380000000", + "Kleinmaischeid (Neuwied - Rheinland-Pfalz)": "071380000000", + "Stebach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Marienhausen (Neuwied - Rheinland-Pfalz)": "071380000000", + "Dattenberg (Neuwied - Rheinland-Pfalz)": "071380000000", + "Leubsdorf (Neuwied - Rheinland-Pfalz)": "071380000000", + "Linz am Rhein, Stadt (Neuwied - Rheinland-Pfalz)": "071380000000", + "Ockenfels (Neuwied - Rheinland-Pfalz)": "071380000000", + "Sankt Katharinen (Landkreis Neuwied) (Neuwied - Rheinland-Pfalz)": "071380000000", + "Vettelschoß (Neuwied - Rheinland-Pfalz)": "071380000000", + "Kasbach-Ohlenberg (Neuwied - Rheinland-Pfalz)": "071380000000", + "Dernbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Döttesfeld (Neuwied - Rheinland-Pfalz)": "071380000000", + "Dürrholz (Neuwied - Rheinland-Pfalz)": "071380000000", + "Hanroth (Neuwied - Rheinland-Pfalz)": "071380000000", + "Harschbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Linkenbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Niederhofen (Neuwied - Rheinland-Pfalz)": "071380000000", + "Niederwambach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Oberdreis (Neuwied - Rheinland-Pfalz)": "071380000000", + "Puderbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Ratzert (Neuwied - Rheinland-Pfalz)": "071380000000", + "Raubach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Rodenbach bei Puderbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Steimel (Neuwied - Rheinland-Pfalz)": "071380000000", + "Urbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Woldert (Neuwied - Rheinland-Pfalz)": "071380000000", + "Bruchhausen (Neuwied - Rheinland-Pfalz)": "071380000000", + "Erpel (Neuwied - Rheinland-Pfalz)": "071380000000", + "Rheinbreitbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Unkel, Stadt (Neuwied - Rheinland-Pfalz)": "071380000000", + "Anhausen (Neuwied - Rheinland-Pfalz)": "071380000000", + "Bonefeld (Neuwied - Rheinland-Pfalz)": "071380000000", + "Breitscheid (Neuwied - Rheinland-Pfalz)": "071380000000", + "Hausen (Wied) (Neuwied - Rheinland-Pfalz)": "071380000000", + "Datzeroth (Neuwied - Rheinland-Pfalz)": "071380000000", + "Ehlscheid (Neuwied - Rheinland-Pfalz)": "071380000000", + "Hardert (Neuwied - Rheinland-Pfalz)": "071380000000", + "Hümmerich (Neuwied - Rheinland-Pfalz)": "071380000000", + "Kurtscheid (Neuwied - Rheinland-Pfalz)": "071380000000", + "Meinborn (Neuwied - Rheinland-Pfalz)": "071380000000", + "Melsbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Niederbreitbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Oberhonnefeld-Gierend (Neuwied - Rheinland-Pfalz)": "071380000000", + "Oberraden (Neuwied - Rheinland-Pfalz)": "071380000000", + "Rengsdorf (Neuwied - Rheinland-Pfalz)": "071380000000", + "Roßbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Rüscheid (Neuwied - Rheinland-Pfalz)": "071380000000", + "Straßenhaus (Neuwied - Rheinland-Pfalz)": "071380000000", + "Thalhausen (Neuwied - Rheinland-Pfalz)": "071380000000", + "Waldbreitbach (Neuwied - Rheinland-Pfalz)": "071380000000", + "Boppard, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Alterkülz (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Bell (Hunsrück) (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Beltheim (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Braunshorn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Buch (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Gödenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hasselbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hollnich (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kastellaun, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Korweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Michelbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Roth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Spesenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Uhler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Dommershausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mastershausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Lahr (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mörsdorf (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Zilshausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Bärenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Belg (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Büchenbeuren (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Dickenschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Dill (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Dillendorf (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Gehlweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Gemünden (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hahn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hecken (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Heinzenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Henau (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hirschfeld (Hunsrück) (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kappel (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kirchberg (Hunsrück), Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kludenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Laufersweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Lautzenhausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Lindenschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Maitzborn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Metzenhausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Nieder Kostenz (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Niedersohren (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Niederweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Ober Kostenz (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Raversbeuren (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Reckershausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Rödelhausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Rödern (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Rohrbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Schlierschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Schwarzen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Sohren (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Sohrschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Todenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Unzenberg (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Wahlenau (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Womrath (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Woppenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Würrich (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Altweidelbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Argenthal (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Belgweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Benzweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Bergenhausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Biebern (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Bubach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Budenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Dichtelbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Ellern (Hunsrück) (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Erbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Fronhofen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Holzbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Horn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Keidelheim (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kisselbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Klosterkumbd (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Külz (Hunsrück) (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kümbdchen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Laubach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Liebshausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mengerschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mörschbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mutterschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Nannhausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Neuerkirch (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Niederkumbd (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Ohlweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Oppertshausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Pleizenhausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Ravengiersburg (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Rayerschied (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Reich (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Rheinböllen, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Riegenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Riesweiler (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Sargenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Schnorbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Schönborn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Simmern/ Hunsrück, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Steinbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Tiefenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Wahlbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Wüschheim (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Badenhard (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Bickenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Birkheim (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Damscheid (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Dörth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Emmelshausen, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Gondershausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Halsenbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hausbay (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Hungenroth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Karbach (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Kratzenburg (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Laudert (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Leiningen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Lingerhahn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Maisborn (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mermuth (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Mühlpfad (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Ney (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Niederburg (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Niedert (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Norath (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Oberwesel, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Perscheid (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Pfalzfeld (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Sankt Goar, Stadt (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Schwall (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Thörlingen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Urbar (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Utzenhain (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Wiebelsheim (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Beulich (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Morshausen (Rhein-Hunsrück-Kreis - Rheinland-Pfalz)": "071400000000", + "Lahnstein, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Altendiez (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Aull (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Birlenbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Charlottenberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Cramberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Diez, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dörnberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Eppenrod (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Geilnau (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Gückingen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Hambach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Heistenbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Hirschberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Holzappel (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Holzheim (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Horhausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Isselbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Langenscheid (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Laurenburg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Scheidt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Steinsberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Wasenbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Balduinstein (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Berg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Bettendorf (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Bogel (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Buch (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Ehr (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Endlichhofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Eschbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Gemmerich (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Himmighofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Holzhausen an der Haide (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Hunzel (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kasdorf (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kehlbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Lautert (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Lipporn (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Marienfels (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Miehlen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Nastätten, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Niederbachheim (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Niederwallmenach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Oberbachheim (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Obertiefenbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Oberwallmenach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Oelsberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Hainau (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Rettershain (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Ruppertshofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Strüth (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Weidenbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Welterod (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Winterwerb (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Diethardt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Auel (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Bornich (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dachsenhausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dahlheim (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dörscheid (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Filsen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kamp-Bornhofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kaub, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kestert (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Lierschied (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Lykershausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Nochern (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Osterspai (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Patersberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Prath (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Reichenberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Reitzenhain (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Sankt Goarshausen, Loreleystadt, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Sauerthal (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Weisel (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Weyer (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Braubach, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Attenhausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Bad Ems, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Becheln (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dausenau (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dessighofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dienethal (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dornholzhausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Fachbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Frücht (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Geisig (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Hömberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kemmenau (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Lollschied (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Miellen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Misselberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Nassau, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Nievern (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Obernhof (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Oberwies (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Pohl (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Schweighausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Seelbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Singhofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Sulzbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Weinähr (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Winden (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Zimmerschied (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Arzbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Allendorf (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Berghausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Berndroth (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Biebrich (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Bremberg (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Burgschwalbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Dörsdorf (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Ebertshausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Eisighofen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Ergeshausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Flacht (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Gutenacker (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Hahnstätten (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Herold (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kaltenholzhausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Katzenelnbogen, Stadt (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Klingelbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Kördorf (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Lohrheim (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Mittelfischbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Mudershausen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Netzbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Niederneisen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Niedertiefenbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Oberfischbach (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Oberneisen (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Reckenroth (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Rettert (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Roth (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Schiesheim (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Schönborn (Rhein-Lahn-Kreis - Rheinland-Pfalz)": "071410000000", + "Bad Marienberg (Westerwald), Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Bölsberg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Dreisbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Fehl-Ritzhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Großseifen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hahn bei Marienberg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hardt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hof (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kirburg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Langenbach bei Kirburg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Lautzenbrücken (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Mörlen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Neunkhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nisterau (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nistertal (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Norken (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Stockhausen-Illfurth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Unnau (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Alpenrod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Astert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Atzelgift (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Borod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Dreifelden (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Gehlert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Giesenhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hachenburg, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hattert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Heimborn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Heuzert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Höchstenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kroppach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kundert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Limbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Linden (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Lochum (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Luckenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Marzhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Merkelbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Mörsbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Mudenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Mündersbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Müschenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nister (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Roßbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Steinebach an der Wied (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Stein-Wingert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Streithausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wahlrod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Welkenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wied (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Winkelbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hilgert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hillscheid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Höhr-Grenzhausen, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kammerforst (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Boden (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Daubach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Eitelborn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Gackenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Girod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Görgeshausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Großholbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Heilberscheid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Heiligenroth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Holler (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Horbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hübingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kadenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Montabaur, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nentershausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Neuhäusel (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Niederelbert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Niedererbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nomborn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Oberelbert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ruppach-Goldhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Simmern (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Stahlhofen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Untershausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Welschneudorf (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Alsbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Breitenau (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Caan (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Deesen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hundsdorf (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nauort (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Oberhaid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ransbach-Baumbach, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Sessenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wirscheid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wittgert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Bretthausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Elsoff (Westerwald) (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hellenhahn-Schellenberg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Homberg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hüblingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Irmtraut (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Liebenscheid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Neunkirchen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Neustadt/ Westerwald (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Niederroßbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nister-Möhrendorf (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Oberrod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Oberroßbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Rehe (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Rennerod, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Salzburg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Seck (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Stein-Neukirch (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Waigandshain (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Waldmühlen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Westernohe (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Willingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Zehnhausen bei Rennerod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ellenhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Freilingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Freirachdorf (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Goddert (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hartenfels (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Herschbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Krümmel (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Marienrachdorf (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Maroth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Maxsain (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Nordhofen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Quirnbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Rückeroth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Schenkelberg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Selters (Westerwald), Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Sessenhausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Steinen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Vielbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wölferlingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ewighausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Weidenhahn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Dreikirchen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hundsangen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Obererbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Steinefrenz (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Weroth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Arnshöfen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Berod bei Wallmerod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Bilkheim (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ettinghausen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hahn am See (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Herschbach (Oberwesterwald) (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kuhnhöfen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Meudt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Molsberg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Niederahr (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Oberahr (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Salz (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wallmerod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Zehnhausen bei Wallmerod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Elbingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Mähren (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ailertchen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Bellingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Berzhahn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Brandscheid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Enspel (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Gemünden (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Girkenroth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Guckheim (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Härtlingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Halbs (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Hergenroth (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Höhn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kaden (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Kölbingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Langenhahn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Pottum (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Rotenhain (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Rothenbach (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Stahlhofen am Wiesensee (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Stockum-Püschen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Weltersburg (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Westerburg, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Willmenrod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Winnen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Bannberscheid (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Dernbach (Westerwald) (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ebernhahn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Helferskirchen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Leuterod (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Mogendorf (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Moschheim (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Ötzingen (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Siershahn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Staudt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Wirges, Stadt (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Niedersayn (Westerwaldkreis - Rheinland-Pfalz)": "071430000000", + "Trier, Stadt": "072110000000", + "Wittlich, Stadt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Morbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bernkastel-Kues, Stadt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Brauneberg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Burgen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Erden (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Gornhausen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Graach an der Mosel (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Hochscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Kesten (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Kleinich (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Kommen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Lieser (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Lösnich (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Longkamp (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Maring-Noviand (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Minheim (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Monzelfeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Mülheim an der Mosel (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Neumagen-Dhron (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Piesport (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Ürzig (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Veldenz (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Wintrich (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Zeltingen-Rachtig (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Berglicht (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Burtscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Deuselbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Dhronecken (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Etgert (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Gielert (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Gräfendhron (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Hilscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Horath (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Immert (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Lückenburg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Malborn (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Merschbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Neunkirchen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Rorodt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Schönberg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Talling (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Thalfang (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Breit (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Büdlich (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Heidenburg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Altrich (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Arenrath (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bergweiler (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bettenfeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Binsfeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bruch (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Dierfeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Dierscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Dodenburg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Dreis (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Eckfeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Eisenschmitt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Esch (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Gipperath (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Gladbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Greimerath (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Großlittgen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Hasborn (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Heckenmünster (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Heidweiler (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Hetzerath (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Hupperath (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Karl (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Klausen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Laufeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Manderscheid, Stadt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Meerfeld (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Minderlittgen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Musweiler (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Niederöfflingen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Niederscheidweiler (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Oberöfflingen (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Oberscheidweiler (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Osann-Monzel (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Pantenburg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Platten (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Plein (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Rivenich (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Salmtal (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Schladt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Schwarzenborn (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Sehlem (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Wallscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Landscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Niersbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bausendorf (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bengel (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Burg (Mosel) (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Diefenbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Enkirch (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Flußbach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Hontheim (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Kinderbeuern (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Kinheim (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Kröv (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Reil (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Starkenburg (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Traben-Trarbach, Stadt (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Willwerscheid (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Lötzbeuren (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Irmenach (Bernkastel-Wittlich - Rheinland-Pfalz)": "072310000000", + "Bitburg, Stadt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Arzfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dackscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dahnen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Daleiden (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dasburg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Eilscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Eschfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Euscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Großkampenberg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hargarten (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Harspelt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Herzfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Irrhausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Jucken (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kesfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kickeshausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kinzenburg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Krautscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lambertsberg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lascheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lauperath (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Leidenborn (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lichtenborn (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lierfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lünebach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lützkampen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Manderscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Mauel (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Merlscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niederpierscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberpierscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Olmscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Pintesfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Plütscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Preischeid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Reiff (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Reipeldingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Roscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sengerich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sevenig (Our) (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Strickscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Waxweiler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Üttfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Affler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Alsdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Altscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ammeldingen an der Our (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ammeldingen bei Neuerburg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Bauler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Berkoth (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Berscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Biesdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Bollendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Burg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dauwelshausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Echternacherbrück (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Emmelbaum (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ernzen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ferschweiler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Fischbach-Oberraden (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Geichlingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gemünd (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gentingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Heilbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Herbstmühle (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Holsthum (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hommerdingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hütten (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hüttingen bei Lahr (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Irrel (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Karlshausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kaschenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Keppeshausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Körperich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Koxhausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kruchten (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lahr (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Leimbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Menningen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Mettendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Minden (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Muxerath (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Nasingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Neuerburg, Stadt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niedergeckler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niederraden (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niederweis (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niehl (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Nusbaum (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Obergeckler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Utscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Peffingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Plascheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Prümzurlay (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Rodershausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Roth an der Our (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Schankweiler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Scheitenkorb (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Scheuern (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sevenig bei Neuerburg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sinspelt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Übereisenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Uppershausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Waldhof-Falkenstein (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wallendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Weidingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Zweifelscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Eisenach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gilzem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Auw bei Prüm (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Bleialf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Brandscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Buchet (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Büdesheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dingdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Feuerscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Fleringen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Giesdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Weinsheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gondenbrett (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Großlangenfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Habscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Heckhuscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Heisdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kleinlangenfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Lasel (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Masthorn (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Matzerath (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Mützenich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Neuendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niederlauch (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Nimshuscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Nimsreuland (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberlascheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberlauch (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Olzheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Orlenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Pittenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Pronsfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Prüm, Stadt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Rommersheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Roth bei Prüm (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Schönecken (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Schwirzheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Seiwerath (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sellerich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wallersheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Watzerath (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wawern (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Winringen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Winterscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Winterspelt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hersdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Auw an der Kyll (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Beilingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Herforst (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hosten (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Philippsheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Preist (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Speicher, Stadt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Orenhofen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Spangdahlem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Badem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Baustert (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Bettingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Bickendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Biersdorf am See (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Birtlingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Brecht (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dahlem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dockendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Dudeldorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Echtershausen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ehlenz (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Enzen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Eßlingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Etteldorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Feilsdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Fließem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gindorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gondorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Halsdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hamm (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Heilenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hütterscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Hüttingen an der Kyll (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Idenheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Idesheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ingendorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kyllburg, Stadt (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Kyllburgweiler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Ließem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Malberg (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Malbergweich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Meckel (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Messerich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Metterich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Mülbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Nattenheim (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Neidenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niederstedem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Niederweiler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberstedem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberweiler (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberweis (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Olsdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Orsfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Pickließem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Rittersdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Röhl (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sankt Thomas (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Scharfbillig (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Schleid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Seffern (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sefferweich (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Stockem (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Sülm (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Trimport (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Usch (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wettlingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wiersdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wilsecker (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wolsfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Balesfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Burbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Gransdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Neuheilenbach (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Oberkail (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Seinsfeld (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Steinborn (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Zendscheid (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Wißmannsdorf (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Brimingen (Eifelkreis Bitburg-Prüm - Rheinland-Pfalz)": "072320000000", + "Betteldorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Bleckhausen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Brockscheid (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Darscheid (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Demerath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Deudesfeld (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Dockweiler (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Dreis-Brück (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Ellscheid (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Gefell (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Gillenfeld (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Hinterweiler (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Hörscheid (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Immerath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kirchweiler (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kradenbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Mehren (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Meisburg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Mückeln (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Nerdlen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Niederstadtfeld (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Oberstadtfeld (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Sarmersbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Saxler (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Schalkenmehren (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Schönbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Schutz (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Steineberg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Steiningen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Strohn (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Strotzbüsch (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Udler (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Üdersdorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Utzerath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Wallenborn (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Weidenbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Winkel (Eifel) (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Daun, Stadt (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Beinhausen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Boxberg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Hörschhausen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Katzwinkel (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Neichen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Arbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Bereborn (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Berenbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Bodenbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Bongard (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Borler (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Brücktal (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Drees (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Gelenberg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Gunderath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Höchstberg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Horperath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kaperich (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kelberg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kirsbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kötterichen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kolverath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Lirstal (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Mannebach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Mosbruch (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Nitz (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Oberelz (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Reimerath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Retterath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Sassen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Uersfeld (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Ueß (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Welcherath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Basberg (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Berlingen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Berndorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Birgel (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Dohm-Lammersdorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Esch (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Feusdorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Gerolstein, Stadt (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Gönnersdorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Hillesheim, Stadt (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Hohenfels-Essingen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Jünkerath (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kalenborn-Scheuern (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kerpen (Eifel) (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Lissendorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Neroth (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Oberbettingen (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Oberehe-Stroheich (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Pelm (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Rockeskyll (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Salm (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Üxheim (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Walsdorf (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Wiesbaum (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Birresborn (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Densborn (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Duppach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Hallschlag (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kerschenbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Kopp (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Mürlenbach (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Nohn (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Ormont (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Reuth (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Scheid (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Schüller (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Stadtkyll (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Steffeln (Vulkaneifel - Rheinland-Pfalz)": "072330000000", + "Bescheid (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Beuren (Hochwald) (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Damflos (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Geisfeld (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Grimburg (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Gusenburg (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Hermeskeil, Stadt (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Hinzert-Pölert (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Naurath (Wald) (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Neuhütten (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Rascheid (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Reinsfeld (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Züsch (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kanzem (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Konz, Stadt (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Nittel (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Oberbillig (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Onsdorf (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Pellingen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Tawern (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Temmels (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Wasserliesch (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Wawern (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Wellen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Wiltingen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Bonerath (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Farschweiler (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Gusterath (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Gutweiler (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Herl (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Hinzenburg (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Holzerath (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kasel (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Korlingen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Lorscheid (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Mertesdorf (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Morscheid (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Ollmuth (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Osburg (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Pluwig (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Riveris (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Schöndorf (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Sommerau (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Thomm (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Waldrach (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Bekond (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Detzem (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Ensch (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Fell (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Föhren (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kenn (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Klüsserath (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Köwerich (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Leiwen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Longen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Longuich (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Mehring (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Naurath (Eifel) (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Pölich (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Riol (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Schleich (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Schweich, Stadt (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Thörnich (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Trittenheim (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Aach (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Franzenheim (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Hockweiler (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Igel (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kordel (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Langsur (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Newel (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Ralingen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Trierweiler (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Zemmer (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Welschbillig (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Ayl (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Baldringen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Fisch (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Freudenburg (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Greimerath (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Heddert (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Hentern (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Irsch (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kastel-Staadt (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kell am See (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Kirf (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Lampaden (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Mandern (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Mannebach (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Ockfen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Palzem (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Paschel (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Saarburg, Stadt (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Schillingen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Schoden (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Schömerich (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Serrig (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Taben-Rodt (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Trassem (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Vierherrenborn (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Waldweiler (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Wincheringen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Zerf (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Merzkirchen (Trier-Saarburg - Rheinland-Pfalz)": "072350000000", + "Frankenthal (Pfalz), Stadt": "073110000000", + "Kaiserslautern, Stadt": "073120000000", + "Landau in der Pfalz, Stadt": "073130000000", + "Ludwigshafen am Rhein, Stadt": "073140000000", + "Mainz, Stadt": "073150000000", + "Neustadt an der Weinstraße, Stadt": "073160000000", + "Pirmasens, Stadt": "073170000000", + "Speyer, Stadt": "073180000000", + "Worms, Stadt": "073190000000", + "Zweibrücken, Stadt": "073200000000", + "Alzey, Stadt (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Albig (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bechenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bechtolsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bermersheim vor der Höhe (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Biebelnheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bornheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Dintesheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Eppelsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Erbes-Büdesheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Esselborn (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Flomborn (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Flonheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Framersheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Freimersheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gau-Heppenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gau-Odernheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Kettenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Lonsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Mauchenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Nack (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Nieder-Wiesen (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Ober-Flörsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Offenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wahlheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Alsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Eich (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gimbsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Hamm am Rhein (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Mettenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Flörsheim-Dalsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Hohen-Sülzen (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Mölsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Mörstadt (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Monsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Offstein (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wachenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Eckelsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gau-Bickelheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gumbsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Siefersheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Stein-Bockenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wendelsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wöllstein (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wonsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Armsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Ensheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gabsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gau-Weinheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Partenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Saulheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Schornsheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Spiesheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Sulzheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Udenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Vendersheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wallertheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Wörrstadt, Stadt (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bechtheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bermersheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Hochborn (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Dittelsheim-Heßloch (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Frettenheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gundersheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Gundheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Hangen-Weisheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Monzernheim (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Osthofen, Stadt (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Westhofen (Alzey-Worms - Rheinland-Pfalz)": "073310000000", + "Bad Dürkheim, Stadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Grünstadt, Stadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Haßloch (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Deidesheim, Stadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Forst an der Weinstraße (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Meckenheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Niederkirchen bei Deidesheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Ruppertsberg (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Bobenheim am Berg (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Dackenheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Erpolzheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Freinsheim, Stadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Herxheim am Berg (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Kallstadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Weisenheim am Berg (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Weisenheim am Sand (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Elmstein (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Esthal (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Frankeneck (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Lambrecht (Pfalz), Stadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Lindenberg (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Neidenfels (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Weidenthal (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Ellerstadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Friedelsheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Gönnheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Wachenheim an der Weinstraße, Stadt (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Altleiningen (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Battenberg (Pfalz) (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Bissersheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Bockenheim an der Weinstraße (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Carlsberg (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Dirmstein (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Ebertsheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Gerolsheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Großkarlbach (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Hettenleidelheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Kindenheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Kirchheim an der Weinstraße (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Kleinkarlbach (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Laumersheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Mertesheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Neuleiningen (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Obersülzen (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Obrigheim (Pfalz) (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Quirnheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Tiefenthal (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Wattenheim (Bad Dürkheim - Rheinland-Pfalz)": "073320000000", + "Eisenberg (Pfalz), Stadt (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Kerzenheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Ramsen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Albisheim (Pfrimm) (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Biedesheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Bubenheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Dreisen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Einselthum (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Göllheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Immesheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Lautersheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Ottersheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Rüssingen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Standenbühl (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Weitersweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Zellertal (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Bennhausen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Bischheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Bolanden (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Dannenfels (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Gauersheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Ilbesheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Jakobsweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Kirchheimbolanden, Stadt (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Kriegsfeld (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Marnheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Mörsfeld (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Morschheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Oberwiesen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Orbis (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Rittersheim (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Stetten (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Börrstadt (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Breunigweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Falkenstein (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Gonbach (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Höringen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Imsbach (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Lohnsfeld (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Münchweiler an der Alsenz (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Schweisweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Sippersfeld (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Steinbach am Donnersberg (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Wartenberg-Rohrbach (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Winnweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Alsenz (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Bayerfeld-Steckweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Bisterschied (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Dielkirchen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Dörrmoschel (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Finkenbach-Gersweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Gaugrehweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Gehrweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Gerbach (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Gundersweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Imsweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Kalkofen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Katzenbach (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Mannweiler-Cölln (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Münsterappel (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Niederhausen an der Appel (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Niedermoschel (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Oberhausen an der Appel (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Obermoschel, Stadt (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Oberndorf (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Ransweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Ruppertsecken (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Sankt Alban (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Schiersfeld (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Schönborn (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Sitters (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Stahlberg (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Teschenmoschel (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Unkenbach (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Waldgrehweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Winterborn (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Würzweiler (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Rathskirchen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Reichsthal (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Seelen (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Rockenhausen, Stadt (Donnersbergkreis - Rheinland-Pfalz)": "073330000000", + "Germersheim, Stadt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Wörth am Rhein, Stadt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Bellheim (Germersheim - Rheinland-Pfalz)": "073340000000", + "Knittelsheim (Germersheim - Rheinland-Pfalz)": "073340000000", + "Ottersheim bei Landau (Germersheim - Rheinland-Pfalz)": "073340000000", + "Zeiskam (Germersheim - Rheinland-Pfalz)": "073340000000", + "Berg (Pfalz) (Germersheim - Rheinland-Pfalz)": "073340000000", + "Hagenbach, Stadt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Neuburg am Rhein (Germersheim - Rheinland-Pfalz)": "073340000000", + "Scheibenhardt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Hatzenbühl (Germersheim - Rheinland-Pfalz)": "073340000000", + "Jockgrim (Germersheim - Rheinland-Pfalz)": "073340000000", + "Neupotz (Germersheim - Rheinland-Pfalz)": "073340000000", + "Rheinzabern (Germersheim - Rheinland-Pfalz)": "073340000000", + "Erlenbach bei Kandel (Germersheim - Rheinland-Pfalz)": "073340000000", + "Freckenfeld (Germersheim - Rheinland-Pfalz)": "073340000000", + "Kandel, Stadt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Minfeld (Germersheim - Rheinland-Pfalz)": "073340000000", + "Steinweiler (Germersheim - Rheinland-Pfalz)": "073340000000", + "Vollmersweiler (Germersheim - Rheinland-Pfalz)": "073340000000", + "Winden (Germersheim - Rheinland-Pfalz)": "073340000000", + "Freisbach (Germersheim - Rheinland-Pfalz)": "073340000000", + "Lingenfeld (Germersheim - Rheinland-Pfalz)": "073340000000", + "Lustadt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Schwegenheim (Germersheim - Rheinland-Pfalz)": "073340000000", + "Weingarten (Pfalz) (Germersheim - Rheinland-Pfalz)": "073340000000", + "Westheim (Pfalz) (Germersheim - Rheinland-Pfalz)": "073340000000", + "Hördt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Kuhardt (Germersheim - Rheinland-Pfalz)": "073340000000", + "Leimersheim (Germersheim - Rheinland-Pfalz)": "073340000000", + "Rülzheim (Germersheim - Rheinland-Pfalz)": "073340000000", + "Bruchmühlbach-Miesau (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Gerhardsbrunn (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Lambsborn (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Langwieden (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Martinshöhe (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Enkenbach-Alsenborn (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Fischbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Frankenstein (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Hochspeyer (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Mehlingen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Neuhemsbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Waldleiningen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Sembach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Hütschenhausen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Kottweiler-Schwanden (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Niedermohr (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Ramstein-Miesenbach, Stadt (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Steinwenden (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Erzenhausen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Eulenbis (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Kollweiler (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Mackenbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Rodenbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Schwedelbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Weilerbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Reichenbach-Steegen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Frankelbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Heiligenmoschel (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Hirschhorn/ Pfalz (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Katzweiler (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Mehlbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Niederkirchen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Olsbrücken (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Otterbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Otterberg, Stadt (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Schallodenbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Schneckenhausen (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Sulzbachtal (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Bann (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Hauptstuhl (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Kindsbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Krickenbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Landstuhl, Sickingenstadt, Stadt (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Linden (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Mittelbrunn (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Oberarnbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Queidersbach (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Stelzenberg (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Trippstadt (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Schopp (Kaiserslautern - Rheinland-Pfalz)": "073350000000", + "Adenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Aschbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Buborn (Kusel - Rheinland-Pfalz)": "073360000000", + "Cronenberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Deimberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Einöllen (Kusel - Rheinland-Pfalz)": "073360000000", + "Eßweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Ginsweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Glanbrücken (Kusel - Rheinland-Pfalz)": "073360000000", + "Grumbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Hausweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Hefersweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Heinzenhausen (Kusel - Rheinland-Pfalz)": "073360000000", + "Herren-Sulzbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Hinzweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Hohenöllen (Kusel - Rheinland-Pfalz)": "073360000000", + "Homberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Hoppstädten (Kusel - Rheinland-Pfalz)": "073360000000", + "Jettenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Kappeln (Kusel - Rheinland-Pfalz)": "073360000000", + "Kirrweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Kreimbach-Kaulbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Langweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Lauterecken, Stadt (Kusel - Rheinland-Pfalz)": "073360000000", + "Lohnweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Medard (Kusel - Rheinland-Pfalz)": "073360000000", + "Merzweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Nerzweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Nußbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Oberweiler im Tal (Kusel - Rheinland-Pfalz)": "073360000000", + "Oberweiler-Tiefenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Odenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Offenbach-Hundheim (Kusel - Rheinland-Pfalz)": "073360000000", + "Reipoltskirchen (Kusel - Rheinland-Pfalz)": "073360000000", + "Relsberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Rothselberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Rutsweiler an der Lauter (Kusel - Rheinland-Pfalz)": "073360000000", + "Sankt Julian (Kusel - Rheinland-Pfalz)": "073360000000", + "Unterjeckenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Wiesweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Wolfstein, Stadt (Kusel - Rheinland-Pfalz)": "073360000000", + "Altenkirchen (Kusel - Rheinland-Pfalz)": "073360000000", + "Börsborn (Kusel - Rheinland-Pfalz)": "073360000000", + "Breitenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Brücken (Pfalz) (Kusel - Rheinland-Pfalz)": "073360000000", + "Dittweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Dunzweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Frohnhofen (Kusel - Rheinland-Pfalz)": "073360000000", + "Glan-Münchweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Gries (Kusel - Rheinland-Pfalz)": "073360000000", + "Henschtal (Kusel - Rheinland-Pfalz)": "073360000000", + "Herschweiler-Pettersheim (Kusel - Rheinland-Pfalz)": "073360000000", + "Hüffler (Kusel - Rheinland-Pfalz)": "073360000000", + "Krottelbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Langenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Nanzdietschweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Ohmbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Rehweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Schönenberg-Kübelberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Steinbach am Glan (Kusel - Rheinland-Pfalz)": "073360000000", + "Wahnwegen (Kusel - Rheinland-Pfalz)": "073360000000", + "Waldmohr, Stadt (Kusel - Rheinland-Pfalz)": "073360000000", + "Matzenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Quirnbach/ Pfalz (Kusel - Rheinland-Pfalz)": "073360000000", + "Albessen (Kusel - Rheinland-Pfalz)": "073360000000", + "Altenglan (Kusel - Rheinland-Pfalz)": "073360000000", + "Blaubach (Kusel - Rheinland-Pfalz)": "073360000000", + "Bosenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Dennweiler-Frohnbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Ehweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Elzweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Erdesbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Etschberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Föckelberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Haschbach am Remigiusberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Herchweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Horschbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Körborn (Kusel - Rheinland-Pfalz)": "073360000000", + "Konken (Kusel - Rheinland-Pfalz)": "073360000000", + "Kusel, Stadt (Kusel - Rheinland-Pfalz)": "073360000000", + "Neunkirchen am Potzberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Niederalben (Kusel - Rheinland-Pfalz)": "073360000000", + "Niederstaufenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Oberalben (Kusel - Rheinland-Pfalz)": "073360000000", + "Oberstaufenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Pfeffelbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Rammelsbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Rathsweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Reichweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Ruthweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Rutsweiler am Glan (Kusel - Rheinland-Pfalz)": "073360000000", + "Schellweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Selchenbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Thallichtenberg (Kusel - Rheinland-Pfalz)": "073360000000", + "Theisbergstegen (Kusel - Rheinland-Pfalz)": "073360000000", + "Ulmet (Kusel - Rheinland-Pfalz)": "073360000000", + "Welchweiler (Kusel - Rheinland-Pfalz)": "073360000000", + "Bedesbach (Kusel - Rheinland-Pfalz)": "073360000000", + "Albersweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Dernbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Eußerthal (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Gossersweiler-Stein (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Münchweiler am Klingbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Ramberg (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Rinnthal (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Silz (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Völkersweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Waldhambach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Waldrohrbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Wernersberg (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Annweiler am Trifels, Stadt (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Bad Bergzabern, Stadt (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Barbelroth (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Birkenhördt (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Böllenborn (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Dierbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Dörrenbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Gleiszellen-Gleishorbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Hergersweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Kapellen-Drusweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Kapsweyer (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Klingenmünster (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Niederhorbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Niederotterbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Oberhausen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Oberotterbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Oberschlettenbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Pleisweiler-Oberhofen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Schweigen-Rechtenbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Schweighofen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Steinfeld (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Vorderweidenthal (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Altdorf (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Böbingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Burrweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Edenkoben, Stadt (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Edesheim (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Flemlingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Freimersheim (Pfalz) (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Gleisweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Gommersheim (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Großfischlingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Hainfeld (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Kleinfischlingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Rhodt unter Rietburg (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Roschbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Venningen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Weyher in der Pfalz (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Herxheim bei Landau/ Pfalz (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Herxheimweyher (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Insheim (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Rohrbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Billigheim-Ingenheim (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Birkweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Böchingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Eschbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Frankweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Göcklingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Heuchelheim-Klingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Ilbesheim bei Landau in der Pfalz (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Impflingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Knöringen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Leinsweiler (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Ranschbach (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Siebeldingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Walsheim (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Kirrweiler (Pfalz) (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Maikammer (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Sankt Martin (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Bornheim (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Essingen (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Hochstadt (Pfalz) (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Offenbach an der Queich (Südliche Weinstraße - Rheinland-Pfalz)": "073370000000", + "Bobenheim-Roxheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Böhl-Iggelheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Limburgerhof (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Mutterstadt (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Schifferstadt, Stadt (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Dannstadt-Schauernheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Hochdorf-Assenheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Rödersheim-Gronau (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Birkenheide (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Fußgönheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Maxdorf (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Beindersheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Großniedesheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Heßheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Heuchelheim bei Frankenthal (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Kleinniedesheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Lambsheim (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Dudenhofen (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Hanhofen (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Harthausen (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Römerberg (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Altrip (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Neuhofen (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Otterstadt (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Waldsee (Rhein-Pfalz-Kreis - Rheinland-Pfalz)": "073380000000", + "Bingen am Rhein, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Budenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Ingelheim am Rhein, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Bacharach, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Breitscheid (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Manubach (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Münster-Sarmsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Niederheimbach (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Oberdiebach (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Oberheimbach (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Trechtingshausen (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Waldalgesheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Weiler bei Bingen (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Bodenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Gau-Bischofsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Harxheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Lörzweiler (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Nackenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Appenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Bubenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Engelstadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Gau-Algesheim, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Nieder-Hilbersheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Ober-Hilbersheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Ockenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Schwabenheim an der Selz (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Essenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Jugenheim in Rheinhessen (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Klein-Winternheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Nieder-Olm, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Ober-Olm (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Sörgenloch (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Stadecken-Elsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Zornheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Dalheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Dexheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Dienheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Dolgesheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Eimsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Friesenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Guntersblum (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Hahnheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Hillesheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Köngernheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Ludwigshöhe (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Mommenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Nierstein, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Oppenheim, Stadt (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Selzen (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Uelversheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Undenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Weinolsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Wintersheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Dorn-Dürkheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Aspisheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Badenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Gensingen (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Grolsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Horrweiler (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Sankt Johann (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Sprendlingen (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Welgesheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Zotzenheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Wolfsheim (Mainz-Bingen - Rheinland-Pfalz)": "073390000000", + "Bobenthal (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Busenberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Dahn, Stadt (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Erfweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Erlenbach bei Dahn (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Fischbach bei Dahn (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hirschthal (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Ludwigswinkel (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Niederschlettenbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Nothweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Rumbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schindhard (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schönau (Pfalz) (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Bruchweiler-Bärenbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Bundenthal (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Darstein (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Dimbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hauenstein (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hinterweidenthal (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Lug (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schwanheim (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Spirkelbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Wilgartswiesen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Eppenbrunn (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hilst (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Kröppen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Lemberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Obersimten (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Ruppertsweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schweix (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Trulben (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Vinningen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Bottenbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Clausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Donsieders (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Leimen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Merzalben (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Münchweiler an der Rodalb (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Rodalben, Stadt (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Geiselberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Heltersberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hermersberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Höheinöd (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Horbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schmalenberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Steinalben (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Waldfischbach-Burgalben (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Althornbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Battweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Bechhofen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Contwig (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Dellfeld (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Dietrichingen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Großbundenbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Großsteinhausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hornbach, Stadt (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Käshofen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Kleinbundenbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Kleinsteinhausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Mauschbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Riedelberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Rosenkopf (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Walshausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Wiesbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Herschberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Hettenhausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Höheischweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Höhfröschen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Nünschweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Petersberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Saalstadt (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schauerberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Thaleischweiler-Fröschen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Weselberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Biedershausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Knopp-Labach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Krähenberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Maßweiler (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Obernheim-Kirchenarnbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Reifenberg (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Rieschweiler-Mühlbach (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Schmitshausen (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Wallhalben (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Winterbach (Pfalz) (Südwestpfalz - Rheinland-Pfalz)": "073400000000", + "Stuttgart, Landeshauptstadt": "081110000000", + "Böblingen, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Leonberg, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Magstadt (Böblingen - Baden-Württemberg)": "081150000000", + "Renningen, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Rutesheim, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Schönaich (Böblingen - Baden-Württemberg)": "081150000000", + "Sindelfingen, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Weil der Stadt, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Weil im Schönbuch (Böblingen - Baden-Württemberg)": "081150000000", + "Weissach (Böblingen - Baden-Württemberg)": "081150000000", + "Aidlingen (Böblingen - Baden-Württemberg)": "081150000000", + "Grafenau (Böblingen - Baden-Württemberg)": "081150000000", + "Ehningen (Böblingen - Baden-Württemberg)": "081150000000", + "Gärtringen (Böblingen - Baden-Württemberg)": "081150000000", + "Deckenpfronn (Böblingen - Baden-Württemberg)": "081150000000", + "Herrenberg, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Nufringen (Böblingen - Baden-Württemberg)": "081150000000", + "Altdorf (Böblingen - Baden-Württemberg)": "081150000000", + "Hildrizhausen (Böblingen - Baden-Württemberg)": "081150000000", + "Holzgerlingen, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Bondorf (Böblingen - Baden-Württemberg)": "081150000000", + "Gäufelden (Böblingen - Baden-Württemberg)": "081150000000", + "Mötzingen (Böblingen - Baden-Württemberg)": "081150000000", + "Jettingen (Böblingen - Baden-Württemberg)": "081150000000", + "Steinenbronn (Böblingen - Baden-Württemberg)": "081150000000", + "Waldenbuch, Stadt (Böblingen - Baden-Württemberg)": "081150000000", + "Denkendorf (Esslingen - Baden-Württemberg)": "081160000000", + "Esslingen am Neckar, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Neuhausen auf den Fildern (Esslingen - Baden-Württemberg)": "081160000000", + "Wernau (Neckar), Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Aichwald (Esslingen - Baden-Württemberg)": "081160000000", + "Filderstadt, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Leinfelden-Echterdingen, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Ostfildern, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Aichtal, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Dettingen unter Teck (Esslingen - Baden-Württemberg)": "081160000000", + "Kirchheim unter Teck, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Notzingen (Esslingen - Baden-Württemberg)": "081160000000", + "Erkenbrechtsweiler (Esslingen - Baden-Württemberg)": "081160000000", + "Owen, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Lenningen (Esslingen - Baden-Württemberg)": "081160000000", + "Altdorf (Esslingen - Baden-Württemberg)": "081160000000", + "Altenriet (Esslingen - Baden-Württemberg)": "081160000000", + "Bempflingen (Esslingen - Baden-Württemberg)": "081160000000", + "Neckartailfingen (Esslingen - Baden-Württemberg)": "081160000000", + "Neckartenzlingen (Esslingen - Baden-Württemberg)": "081160000000", + "Schlaitdorf (Esslingen - Baden-Württemberg)": "081160000000", + "Beuren (Esslingen - Baden-Württemberg)": "081160000000", + "Kohlberg (Esslingen - Baden-Württemberg)": "081160000000", + "Neuffen, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Frickenhausen (Esslingen - Baden-Württemberg)": "081160000000", + "Großbettlingen (Esslingen - Baden-Württemberg)": "081160000000", + "Nürtingen, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Oberboihingen (Esslingen - Baden-Württemberg)": "081160000000", + "Unterensingen (Esslingen - Baden-Württemberg)": "081160000000", + "Wolfschlugen (Esslingen - Baden-Württemberg)": "081160000000", + "Altbach (Esslingen - Baden-Württemberg)": "081160000000", + "Deizisau (Esslingen - Baden-Württemberg)": "081160000000", + "Plochingen, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Baltmannsweiler (Esslingen - Baden-Württemberg)": "081160000000", + "Hochdorf (Esslingen - Baden-Württemberg)": "081160000000", + "Lichtenwald (Esslingen - Baden-Württemberg)": "081160000000", + "Reichenbach an der Fils (Esslingen - Baden-Württemberg)": "081160000000", + "Bissingen an der Teck (Esslingen - Baden-Württemberg)": "081160000000", + "Holzmaden (Esslingen - Baden-Württemberg)": "081160000000", + "Neidlingen (Esslingen - Baden-Württemberg)": "081160000000", + "Ohmden (Esslingen - Baden-Württemberg)": "081160000000", + "Weilheim an der Teck, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Köngen (Esslingen - Baden-Württemberg)": "081160000000", + "Wendlingen am Neckar, Stadt (Esslingen - Baden-Württemberg)": "081160000000", + "Böhmenkirch (Göppingen - Baden-Württemberg)": "081170000000", + "Bad Ditzenbach (Göppingen - Baden-Württemberg)": "081170000000", + "Deggingen (Göppingen - Baden-Württemberg)": "081170000000", + "Ebersbach an der Fils, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Schlierbach (Göppingen - Baden-Württemberg)": "081170000000", + "Eislingen/Fils, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Ottenbach (Göppingen - Baden-Württemberg)": "081170000000", + "Salach (Göppingen - Baden-Württemberg)": "081170000000", + "Bad Überkingen (Göppingen - Baden-Württemberg)": "081170000000", + "Geislingen an der Steige, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Kuchen (Göppingen - Baden-Württemberg)": "081170000000", + "Göppingen, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Schlat (Göppingen - Baden-Württemberg)": "081170000000", + "Wäschenbeuren (Göppingen - Baden-Württemberg)": "081170000000", + "Wangen (Göppingen - Baden-Württemberg)": "081170000000", + "Donzdorf, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Gingen an der Fils (Göppingen - Baden-Württemberg)": "081170000000", + "Süßen, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Lauterstein, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Drackenstein (Göppingen - Baden-Württemberg)": "081170000000", + "Gruibingen (Göppingen - Baden-Württemberg)": "081170000000", + "Hohenstadt (Göppingen - Baden-Württemberg)": "081170000000", + "Mühlhausen im Täle (Göppingen - Baden-Württemberg)": "081170000000", + "Wiesensteig, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Adelberg (Göppingen - Baden-Württemberg)": "081170000000", + "Birenbach (Göppingen - Baden-Württemberg)": "081170000000", + "Börtlingen (Göppingen - Baden-Württemberg)": "081170000000", + "Rechberghausen (Göppingen - Baden-Württemberg)": "081170000000", + "Aichelberg (Göppingen - Baden-Württemberg)": "081170000000", + "Bad Boll (Göppingen - Baden-Württemberg)": "081170000000", + "Dürnau (Göppingen - Baden-Württemberg)": "081170000000", + "Gammelshausen (Göppingen - Baden-Württemberg)": "081170000000", + "Hattenhofen (Göppingen - Baden-Württemberg)": "081170000000", + "Zell unter Aichelberg (Göppingen - Baden-Württemberg)": "081170000000", + "Albershausen (Göppingen - Baden-Württemberg)": "081170000000", + "Uhingen, Stadt (Göppingen - Baden-Württemberg)": "081170000000", + "Eschenbach (Göppingen - Baden-Württemberg)": "081170000000", + "Heiningen (Göppingen - Baden-Württemberg)": "081170000000", + "Asperg, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Ditzingen, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Gerlingen, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Großbottwar, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Kornwestheim, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Ludwigsburg, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Markgröningen, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Möglingen (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Oberstenfeld (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Sachsenheim, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Korntal-Münchingen, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Remseck am Neckar, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Besigheim, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Freudental (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Gemmrigheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Hessigheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Löchgau (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Mundelsheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Walheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Tamm (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Ingersheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Bietigheim-Bissingen, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Bönnigheim, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Erligheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Kirchheim am Neckar (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Pleidelsheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Freiberg am Neckar, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Affalterbach (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Benningen am Neckar (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Erdmannhausen (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Marbach am Neckar, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Hemmingen (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Schwieberdingen (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Murr (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Steinheim an der Murr, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Eberdingen (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Oberriexingen, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Sersheim (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Vaihingen an der Enz, Stadt (Ludwigsburg - Baden-Württemberg)": "081180000000", + "Alfdorf (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Fellbach, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Korb (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Murrhardt, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Rudersberg (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Waiblingen, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Berglen (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Remshalden (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Weinstadt, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Kernen im Remstal (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Allmersbach im Tal (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Althütte (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Auenwald (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Backnang, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Burgstetten (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Kirchberg an der Murr (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Oppenweiler (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Weissach im Tal (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Aspach (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Plüderhausen (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Urbach (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Schorndorf, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Winterbach (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Großerlach (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Spiegelberg (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Sulzbach an der Murr (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Kaisersbach (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Welzheim, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Leutenbach (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Schwaikheim (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Winnenden, Stadt (Rems-Murr-Kreis - Baden-Württemberg)": "081190000000", + "Heilbronn, Universitätsstadt": "081210000000", + "Bad Wimpfen, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Gundelsheim, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Leingarten, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Neudenau, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Wüstenrot (Heilbronn - Baden-Württemberg)": "081250000000", + "Bad Friedrichshall, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Oedheim (Heilbronn - Baden-Württemberg)": "081250000000", + "Offenau (Heilbronn - Baden-Württemberg)": "081250000000", + "Bad Rappenau, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Kirchardt (Heilbronn - Baden-Württemberg)": "081250000000", + "Siegelsbach (Heilbronn - Baden-Württemberg)": "081250000000", + "Brackenheim, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Cleebronn (Heilbronn - Baden-Württemberg)": "081250000000", + "Eppingen, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Gemmingen (Heilbronn - Baden-Württemberg)": "081250000000", + "Ittlingen (Heilbronn - Baden-Württemberg)": "081250000000", + "Flein (Heilbronn - Baden-Württemberg)": "081250000000", + "Talheim (Heilbronn - Baden-Württemberg)": "081250000000", + "Lauffen am Neckar, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Neckarwestheim (Heilbronn - Baden-Württemberg)": "081250000000", + "Nordheim (Heilbronn - Baden-Württemberg)": "081250000000", + "Jagsthausen (Heilbronn - Baden-Württemberg)": "081250000000", + "Möckmühl, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Roigheim (Heilbronn - Baden-Württemberg)": "081250000000", + "Widdern, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Erlenbach (Heilbronn - Baden-Württemberg)": "081250000000", + "Neckarsulm, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Untereisesheim (Heilbronn - Baden-Württemberg)": "081250000000", + "Neuenstadt am Kocher, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Hardthausen am Kocher (Heilbronn - Baden-Württemberg)": "081250000000", + "Langenbrettach (Heilbronn - Baden-Württemberg)": "081250000000", + "Güglingen, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Pfaffenhofen (Heilbronn - Baden-Württemberg)": "081250000000", + "Zaberfeld (Heilbronn - Baden-Württemberg)": "081250000000", + "Löwenstein, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Obersulm (Heilbronn - Baden-Württemberg)": "081250000000", + "Abstatt (Heilbronn - Baden-Württemberg)": "081250000000", + "Beilstein, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Ilsfeld (Heilbronn - Baden-Württemberg)": "081250000000", + "Untergruppenbach (Heilbronn - Baden-Württemberg)": "081250000000", + "Massenbachhausen (Heilbronn - Baden-Württemberg)": "081250000000", + "Schwaigern, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Eberstadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Ellhofen (Heilbronn - Baden-Württemberg)": "081250000000", + "Lehrensteinsfeld (Heilbronn - Baden-Württemberg)": "081250000000", + "Weinsberg, Stadt (Heilbronn - Baden-Württemberg)": "081250000000", + "Bretzfeld (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Schöntal (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Kupferzell (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Neuenstein, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Waldenburg, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Dörzbach (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Krautheim, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Mulfingen (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Ingelfingen, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Künzelsau, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Forchtenberg, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Niedernhall, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Weißbach (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Öhringen, Stadt (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Pfedelbach (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Zweiflingen (Hohenlohekreis - Baden-Württemberg)": "081260000000", + "Blaufelden (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Mainhardt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Schrozberg, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Braunsbach (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Untermünkheim (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Crailsheim, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Satteldorf (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Frankenhardt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Stimpfach (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Kreßberg (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Fichtenau (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Gerabronn, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Langenburg, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Ilshofen, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Vellberg, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Wolpertshausen (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Fichtenberg (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Gaildorf, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Oberrot (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Sulzbach-Laufen (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Bühlertann (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Bühlerzell (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Obersontheim (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Kirchberg an der Jagst, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Rot am See (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Wallhausen (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Michelbach an der Bilz (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Michelfeld (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Schwäbisch Hall, Stadt (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Rosengarten (Schwäbisch Hall - Baden-Württemberg)": "081270000000", + "Creglingen, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Freudenberg, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Külsheim, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Niederstetten, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Weikersheim, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Wertheim, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Lauda-Königshofen, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Assamstadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Bad Mergentheim, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Igersheim (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Boxberg, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Ahorn (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Grünsfeld, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Wittighausen (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Großrinderfeld (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Königheim (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Tauberbischofsheim, Stadt (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Werbach (Main-Tauber-Kreis - Baden-Württemberg)": "081280000000", + "Dischingen (Heidenheim - Baden-Württemberg)": "081350000000", + "Gerstetten (Heidenheim - Baden-Württemberg)": "081350000000", + "Herbrechtingen, Stadt (Heidenheim - Baden-Württemberg)": "081350000000", + "Königsbronn (Heidenheim - Baden-Württemberg)": "081350000000", + "Steinheim am Albuch (Heidenheim - Baden-Württemberg)": "081350000000", + "Giengen an der Brenz, Stadt (Heidenheim - Baden-Württemberg)": "081350000000", + "Hermaringen (Heidenheim - Baden-Württemberg)": "081350000000", + "Heidenheim an der Brenz, Stadt (Heidenheim - Baden-Württemberg)": "081350000000", + "Nattheim (Heidenheim - Baden-Württemberg)": "081350000000", + "Niederstotzingen, Stadt (Heidenheim - Baden-Württemberg)": "081350000000", + "Sontheim an der Brenz (Heidenheim - Baden-Württemberg)": "081350000000", + "Abtsgmünd (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Gschwend (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Lorch, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Neresheim, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Oberkochen, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Essingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Hüttlingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Aalen, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Bopfingen, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Kirchheim am Ries (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Riesbürg (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Adelmannsfelden (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Ellenberg (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Ellwangen (Jagst), Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Jagstzell (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Neuler (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Rosenberg (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Wört (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Rainau (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Lauchheim, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Westhausen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Eschach (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Göggingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Iggingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Leinzell (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Obergröningen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Schechingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Bartholomä (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Böbingen an der Rems (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Heubach, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Heuchlingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Mögglingen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Schwäbisch Gmünd, Stadt (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Waldstetten (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Durlangen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Mutlangen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Ruppertshofen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Spraitbach (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Täferrot (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Stödtlen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Tannhausen (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Unterschneidheim (Ostalbkreis - Baden-Württemberg)": "081360000000", + "Baden-Baden, Stadt": "082110000000", + "Karlsruhe, Stadt": "082120000000", + "Ettlingen, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Malsch (Karlsruhe - Baden-Württemberg)": "082150000000", + "Marxzell (Karlsruhe - Baden-Württemberg)": "082150000000", + "Östringen, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Ubstadt-Weiher (Karlsruhe - Baden-Württemberg)": "082150000000", + "Walzbachtal (Karlsruhe - Baden-Württemberg)": "082150000000", + "Weingarten (Baden) (Karlsruhe - Baden-Württemberg)": "082150000000", + "Karlsbad (Karlsruhe - Baden-Württemberg)": "082150000000", + "Kraichtal, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Pfinztal (Karlsruhe - Baden-Württemberg)": "082150000000", + "Eggenstein-Leopoldshafen (Karlsruhe - Baden-Württemberg)": "082150000000", + "Linkenheim-Hochstetten (Karlsruhe - Baden-Württemberg)": "082150000000", + "Waghäusel, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Rheinstetten, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Stutensee, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Waldbronn (Karlsruhe - Baden-Württemberg)": "082150000000", + "Kronau (Karlsruhe - Baden-Württemberg)": "082150000000", + "Bad Schönborn (Karlsruhe - Baden-Württemberg)": "082150000000", + "Bretten, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Gondelsheim (Karlsruhe - Baden-Württemberg)": "082150000000", + "Bruchsal, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Forst (Karlsruhe - Baden-Württemberg)": "082150000000", + "Hambrücken (Karlsruhe - Baden-Württemberg)": "082150000000", + "Karlsdorf-Neuthard (Karlsruhe - Baden-Württemberg)": "082150000000", + "Graben-Neudorf (Karlsruhe - Baden-Württemberg)": "082150000000", + "Dettenheim (Karlsruhe - Baden-Württemberg)": "082150000000", + "Kürnbach (Karlsruhe - Baden-Württemberg)": "082150000000", + "Oberderdingen (Karlsruhe - Baden-Württemberg)": "082150000000", + "Philippsburg, Stadt (Karlsruhe - Baden-Württemberg)": "082150000000", + "Oberhausen-Rheinhausen (Karlsruhe - Baden-Württemberg)": "082150000000", + "Sulzfeld (Karlsruhe - Baden-Württemberg)": "082150000000", + "Zaisenhausen (Karlsruhe - Baden-Württemberg)": "082150000000", + "Bühlertal (Rastatt - Baden-Württemberg)": "082160000000", + "Forbach (Rastatt - Baden-Württemberg)": "082160000000", + "Gaggenau, Stadt (Rastatt - Baden-Württemberg)": "082160000000", + "Bischweier (Rastatt - Baden-Württemberg)": "082160000000", + "Kuppenheim, Stadt (Rastatt - Baden-Württemberg)": "082160000000", + "Bühl, Stadt (Rastatt - Baden-Württemberg)": "082160000000", + "Ottersweier (Rastatt - Baden-Württemberg)": "082160000000", + "Au am Rhein (Rastatt - Baden-Württemberg)": "082160000000", + "Bietigheim (Rastatt - Baden-Württemberg)": "082160000000", + "Durmersheim (Rastatt - Baden-Württemberg)": "082160000000", + "Elchesheim-Illingen (Rastatt - Baden-Württemberg)": "082160000000", + "Gernsbach, Stadt (Rastatt - Baden-Württemberg)": "082160000000", + "Loffenau (Rastatt - Baden-Württemberg)": "082160000000", + "Weisenbach (Rastatt - Baden-Württemberg)": "082160000000", + "Iffezheim (Rastatt - Baden-Württemberg)": "082160000000", + "Muggensturm (Rastatt - Baden-Württemberg)": "082160000000", + "Ötigheim (Rastatt - Baden-Württemberg)": "082160000000", + "Rastatt, Stadt (Rastatt - Baden-Württemberg)": "082160000000", + "Steinmauern (Rastatt - Baden-Württemberg)": "082160000000", + "Lichtenau, Stadt (Rastatt - Baden-Württemberg)": "082160000000", + "Rheinmünster (Rastatt - Baden-Württemberg)": "082160000000", + "Hügelsheim (Rastatt - Baden-Württemberg)": "082160000000", + "Sinzheim (Rastatt - Baden-Württemberg)": "082160000000", + "Heidelberg, Stadt": "082210000000", + "Mannheim, Universitätsstadt": "082220000000", + "Buchen (Odenwald), Stadt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Mudau (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Hardheim (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Höpfingen (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Walldürn, Stadt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Haßmersheim (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Hüffenhardt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Aglasterhausen (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Neunkirchen (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Schwarzach (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Fahrenbach (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Limbach (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Mosbach, Stadt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Neckarzimmern (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Obrigheim (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Elztal (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Binau (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Neckargerach (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Zwingenberg (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Waldbrunn (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Osterburken, Stadt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Rosenberg (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Ravenstein, Stadt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Billigheim (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Schefflenz (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Adelsheim, Stadt (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Seckach (Neckar-Odenwald-Kreis - Baden-Württemberg)": "082250000000", + "Brühl (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Dossenheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Eppelheim, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Heddesheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Ilvesheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Ketsch (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Ladenburg, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Leimen, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Nußloch (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Oftersheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Plankstadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Sandhausen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Schriesheim, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Schwetzingen, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Walldorf, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Weinheim, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "St. Leon-Rot (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Edingen-Neckarhausen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Hirschberg an der Bergstraße (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Eberbach, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Schönbrunn (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Eschelbronn (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Mauer (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Meckesheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Spechbach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Lobbach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Hemsbach, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Laudenbach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Altlußheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Hockenheim, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Neulußheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Reilingen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Bammental (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Gaiberg (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Neckargemünd, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Wiesenbach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Malsch (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Mühlhausen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Rauenberg, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Heddesbach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Heiligkreuzsteinach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Schönau, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Wilhelmsfeld (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Sinsheim, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Zuzenhausen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Angelbachtal (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Epfenbach (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Neckarbischofsheim, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Neidenstein (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Reichartshausen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Waibstadt, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Helmstadt-Bargen (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Dielheim (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Wiesloch, Stadt (Rhein-Neckar-Kreis - Baden-Württemberg)": "082260000000", + "Pforzheim, Stadt": "082310000000", + "Schömberg (Calw - Baden-Württemberg)": "082350000000", + "Wildberg, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Altensteig, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Egenhausen (Calw - Baden-Württemberg)": "082350000000", + "Simmersfeld (Calw - Baden-Württemberg)": "082350000000", + "Althengstett (Calw - Baden-Württemberg)": "082350000000", + "Gechingen (Calw - Baden-Württemberg)": "082350000000", + "Ostelsheim (Calw - Baden-Württemberg)": "082350000000", + "Simmozheim (Calw - Baden-Württemberg)": "082350000000", + "Dobel (Calw - Baden-Württemberg)": "082350000000", + "Bad Herrenalb, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Bad Liebenzell, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Unterreichenbach (Calw - Baden-Württemberg)": "082350000000", + "Neubulach, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Neuweiler (Calw - Baden-Württemberg)": "082350000000", + "Bad Teinach-Zavelstein, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Oberreichenbach (Calw - Baden-Württemberg)": "082350000000", + "Calw, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Ebhausen (Calw - Baden-Württemberg)": "082350000000", + "Haiterbach, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Nagold, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Rohrdorf (Calw - Baden-Württemberg)": "082350000000", + "Enzklösterle (Calw - Baden-Württemberg)": "082350000000", + "Höfen an der Enz (Calw - Baden-Württemberg)": "082350000000", + "Bad Wildbad, Stadt (Calw - Baden-Württemberg)": "082350000000", + "Birkenfeld (Enzkreis - Baden-Württemberg)": "082360000000", + "Illingen (Enzkreis - Baden-Württemberg)": "082360000000", + "Ispringen (Enzkreis - Baden-Württemberg)": "082360000000", + "Knittlingen, Stadt (Enzkreis - Baden-Württemberg)": "082360000000", + "Niefern-Öschelbronn (Enzkreis - Baden-Württemberg)": "082360000000", + "Keltern (Enzkreis - Baden-Württemberg)": "082360000000", + "Remchingen (Enzkreis - Baden-Württemberg)": "082360000000", + "Straubenhardt (Enzkreis - Baden-Württemberg)": "082360000000", + "Friolzheim (Enzkreis - Baden-Württemberg)": "082360000000", + "Heimsheim, Stadt (Enzkreis - Baden-Württemberg)": "082360000000", + "Mönsheim (Enzkreis - Baden-Württemberg)": "082360000000", + "Wiernsheim (Enzkreis - Baden-Württemberg)": "082360000000", + "Wimsheim (Enzkreis - Baden-Württemberg)": "082360000000", + "Wurmberg (Enzkreis - Baden-Württemberg)": "082360000000", + "Eisingen (Enzkreis - Baden-Württemberg)": "082360000000", + "Kämpfelbach (Enzkreis - Baden-Württemberg)": "082360000000", + "Königsbach-Stein (Enzkreis - Baden-Württemberg)": "082360000000", + "Maulbronn, Stadt (Enzkreis - Baden-Württemberg)": "082360000000", + "Sternenfels (Enzkreis - Baden-Württemberg)": "082360000000", + "Mühlacker, Stadt (Enzkreis - Baden-Württemberg)": "082360000000", + "Ötisheim (Enzkreis - Baden-Württemberg)": "082360000000", + "Engelsbrand (Enzkreis - Baden-Württemberg)": "082360000000", + "Neuenbürg, Stadt (Enzkreis - Baden-Württemberg)": "082360000000", + "Kieselbronn (Enzkreis - Baden-Württemberg)": "082360000000", + "Neulingen (Enzkreis - Baden-Württemberg)": "082360000000", + "Ölbronn-Dürrn (Enzkreis - Baden-Württemberg)": "082360000000", + "Neuhausen (Enzkreis - Baden-Württemberg)": "082360000000", + "Tiefenbronn (Enzkreis - Baden-Württemberg)": "082360000000", + "Alpirsbach, Stadt (Freudenstadt - Baden-Württemberg)": "082370000000", + "Baiersbronn (Freudenstadt - Baden-Württemberg)": "082370000000", + "Loßburg (Freudenstadt - Baden-Württemberg)": "082370000000", + "Dornstetten, Stadt (Freudenstadt - Baden-Württemberg)": "082370000000", + "Glatten (Freudenstadt - Baden-Württemberg)": "082370000000", + "Schopfloch (Freudenstadt - Baden-Württemberg)": "082370000000", + "Waldachtal (Freudenstadt - Baden-Württemberg)": "082370000000", + "Freudenstadt, Stadt (Freudenstadt - Baden-Württemberg)": "082370000000", + "Seewald (Freudenstadt - Baden-Württemberg)": "082370000000", + "Bad Rippoldsau-Schapbach (Freudenstadt - Baden-Württemberg)": "082370000000", + "Empfingen (Freudenstadt - Baden-Württemberg)": "082370000000", + "Eutingen im Gäu (Freudenstadt - Baden-Württemberg)": "082370000000", + "Horb am Neckar, Stadt (Freudenstadt - Baden-Württemberg)": "082370000000", + "Grömbach (Freudenstadt - Baden-Württemberg)": "082370000000", + "Pfalzgrafenweiler (Freudenstadt - Baden-Württemberg)": "082370000000", + "Wörnersberg (Freudenstadt - Baden-Württemberg)": "082370000000", + "Freiburg im Breisgau, Stadt": "083110000000", + "Lenzkirch (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Neuenburg am Rhein, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Vogtsburg im Kaiserstuhl, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Bad Krozingen, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Hartheim am Rhein (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Breisach am Rhein, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Ihringen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Merdingen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Buchenbach (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Kirchzarten (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Oberried (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Stegen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Bollschweil (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Ehrenkirchen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Gundelfingen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Heuweiler (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Ballrechten-Dottingen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Eschbach (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Heitersheim, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Au (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Horben (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Merzhausen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Sölden (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Wittnau (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Breitnau (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Hinterzarten (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Bötzingen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Eichstetten am Kaiserstuhl (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Gottenheim (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Friedenweiler (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Löffingen, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Umkirch (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "March (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Auggen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Badenweiler (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Buggingen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Müllheim, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Sulzburg, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Glottertal (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "St. Märgen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "St. Peter (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Ebringen (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Pfaffenweiler (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Schallstadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Feldberg (Schwarzwald) (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Schluchsee (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Staufen im Breisgau, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Münstertal/Schwarzwald (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Eisenbach (Hochschwarzwald) (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Titisee-Neustadt, Stadt (Breisgau-Hochschwarzwald - Baden-Württemberg)": "083150000000", + "Denzlingen (Emmendingen - Baden-Württemberg)": "083160000000", + "Reute (Emmendingen - Baden-Württemberg)": "083160000000", + "Vörstetten (Emmendingen - Baden-Württemberg)": "083160000000", + "Biederbach (Emmendingen - Baden-Württemberg)": "083160000000", + "Elzach, Stadt (Emmendingen - Baden-Württemberg)": "083160000000", + "Winden im Elztal (Emmendingen - Baden-Württemberg)": "083160000000", + "Emmendingen, Stadt (Emmendingen - Baden-Württemberg)": "083160000000", + "Malterdingen (Emmendingen - Baden-Württemberg)": "083160000000", + "Sexau (Emmendingen - Baden-Württemberg)": "083160000000", + "Teningen (Emmendingen - Baden-Württemberg)": "083160000000", + "Freiamt (Emmendingen - Baden-Württemberg)": "083160000000", + "Herbolzheim, Stadt (Emmendingen - Baden-Württemberg)": "083160000000", + "Kenzingen, Stadt (Emmendingen - Baden-Württemberg)": "083160000000", + "Weisweil (Emmendingen - Baden-Württemberg)": "083160000000", + "Rheinhausen (Emmendingen - Baden-Württemberg)": "083160000000", + "Bahlingen am Kaiserstuhl (Emmendingen - Baden-Württemberg)": "083160000000", + "Endingen am Kaiserstuhl, Stadt (Emmendingen - Baden-Württemberg)": "083160000000", + "Forchheim (Emmendingen - Baden-Württemberg)": "083160000000", + "Riegel am Kaiserstuhl (Emmendingen - Baden-Württemberg)": "083160000000", + "Sasbach am Kaiserstuhl (Emmendingen - Baden-Württemberg)": "083160000000", + "Wyhl am Kaiserstuhl (Emmendingen - Baden-Württemberg)": "083160000000", + "Gutach im Breisgau (Emmendingen - Baden-Württemberg)": "083160000000", + "Simonswald (Emmendingen - Baden-Württemberg)": "083160000000", + "Waldkirch, Stadt (Emmendingen - Baden-Württemberg)": "083160000000", + "Appenweier (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Friesenheim (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Hornberg, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Kehl, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Willstätt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Neuried (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Rheinau, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Achern, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Lauf (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Sasbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Sasbachwalden (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Ettenheim, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Mahlberg, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Ringsheim (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Rust (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Kappel-Grafenhausen (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Berghaupten (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Gengenbach, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Ohlsbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Fischerbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Haslach im Kinzigtal, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Hofstetten (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Mühlenbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Steinach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Gutach (Schwarzwaldbahn) (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Hausach, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Kappelrodeck (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Ottenhöfen im Schwarzwald (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Seebach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Kippenheim (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Lahr/Schwarzwald, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Bad Peterstal-Griesbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Oppenau, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Lautenbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Oberkirch, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Renchen, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Durbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Hohberg (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Offenburg, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Ortenberg (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Schutterwald (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Schuttertal (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Seelbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Meißenheim (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Schwanau (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Oberwolfach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Wolfach, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Biberach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Nordrach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Oberharmersbach (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Zell am Harmersbach, Stadt (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Rheinau, gemeindefreies Gebiet (Ortenaukreis - Baden-Württemberg)": "083170000000", + "Dornhan, Stadt (Rottweil - Baden-Württemberg)": "083250000000", + "Dunningen (Rottweil - Baden-Württemberg)": "083250000000", + "Eschbronn (Rottweil - Baden-Württemberg)": "083250000000", + "Epfendorf (Rottweil - Baden-Württemberg)": "083250000000", + "Oberndorf am Neckar, Stadt (Rottweil - Baden-Württemberg)": "083250000000", + "Fluorn-Winzeln (Rottweil - Baden-Württemberg)": "083250000000", + "Dietingen (Rottweil - Baden-Württemberg)": "083250000000", + "Rottweil, Stadt (Rottweil - Baden-Württemberg)": "083250000000", + "Wellendingen (Rottweil - Baden-Württemberg)": "083250000000", + "Zimmern ob Rottweil (Rottweil - Baden-Württemberg)": "083250000000", + "Deißlingen (Rottweil - Baden-Württemberg)": "083250000000", + "Schenkenzell (Rottweil - Baden-Württemberg)": "083250000000", + "Schiltach, Stadt (Rottweil - Baden-Württemberg)": "083250000000", + "Aichhalden (Rottweil - Baden-Württemberg)": "083250000000", + "Hardt (Rottweil - Baden-Württemberg)": "083250000000", + "Lauterbach (Rottweil - Baden-Württemberg)": "083250000000", + "Schramberg, Stadt (Rottweil - Baden-Württemberg)": "083250000000", + "Sulz am Neckar, Stadt (Rottweil - Baden-Württemberg)": "083250000000", + "Vöhringen (Rottweil - Baden-Württemberg)": "083250000000", + "Bösingen (Rottweil - Baden-Württemberg)": "083250000000", + "Villingendorf (Rottweil - Baden-Württemberg)": "083250000000", + "Bad Dürrheim, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Blumberg, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Königsfeld im Schwarzwald (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "St. Georgen im Schwarzwald, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Vöhrenbach, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Bräunlingen, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Donaueschingen, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Hüfingen, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Furtwangen im Schwarzwald, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Gütenbach (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Schönwald im Schwarzwald (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Schonach im Schwarzwald (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Triberg im Schwarzwald, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Dauchingen (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Mönchweiler (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Niedereschach (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Tuningen (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Unterkirnach (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Villingen-Schwenningen, Stadt (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Brigachtal (Schwarzwald-Baar-Kreis - Baden-Württemberg)": "083260000000", + "Bärenthal (Tuttlingen - Baden-Württemberg)": "083270000000", + "Buchheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Fridingen an der Donau, Stadt (Tuttlingen - Baden-Württemberg)": "083270000000", + "Irndorf (Tuttlingen - Baden-Württemberg)": "083270000000", + "Kolbingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Mühlheim an der Donau, Stadt (Tuttlingen - Baden-Württemberg)": "083270000000", + "Renquishausen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Bubsheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Deilingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Egesheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Gosheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Königsheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Reichenbach am Heuberg (Tuttlingen - Baden-Württemberg)": "083270000000", + "Wehingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Geisingen, Stadt (Tuttlingen - Baden-Württemberg)": "083270000000", + "Immendingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Aldingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Balgheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Böttingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Denkingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Dürbheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Frittlingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Hausen ob Verena (Tuttlingen - Baden-Württemberg)": "083270000000", + "Mahlstetten (Tuttlingen - Baden-Württemberg)": "083270000000", + "Spaichingen, Stadt (Tuttlingen - Baden-Württemberg)": "083270000000", + "Durchhausen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Gunningen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Talheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Trossingen, Stadt (Tuttlingen - Baden-Württemberg)": "083270000000", + "Neuhausen ob Eck (Tuttlingen - Baden-Württemberg)": "083270000000", + "Tuttlingen, Stadt (Tuttlingen - Baden-Württemberg)": "083270000000", + "Wurmlingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Seitingen-Oberflacht (Tuttlingen - Baden-Württemberg)": "083270000000", + "Rietheim-Weilheim (Tuttlingen - Baden-Württemberg)": "083270000000", + "Emmingen-Liptingen (Tuttlingen - Baden-Württemberg)": "083270000000", + "Hilzingen (Konstanz - Baden-Württemberg)": "083350000000", + "Radolfzell am Bodensee, Stadt (Konstanz - Baden-Württemberg)": "083350000000", + "Tengen, Stadt (Konstanz - Baden-Württemberg)": "083350000000", + "Aach, Stadt (Konstanz - Baden-Württemberg)": "083350000000", + "Engen, Stadt (Konstanz - Baden-Württemberg)": "083350000000", + "Mühlhausen-Ehingen (Konstanz - Baden-Württemberg)": "083350000000", + "Büsingen am Hochrhein (Konstanz - Baden-Württemberg)": "083350000000", + "Gailingen am Hochrhein (Konstanz - Baden-Württemberg)": "083350000000", + "Gottmadingen (Konstanz - Baden-Württemberg)": "083350000000", + "Gaienhofen (Konstanz - Baden-Württemberg)": "083350000000", + "Moos (Konstanz - Baden-Württemberg)": "083350000000", + "Öhningen (Konstanz - Baden-Württemberg)": "083350000000", + "Allensbach (Konstanz - Baden-Württemberg)": "083350000000", + "Konstanz, Universitätsstadt (Konstanz - Baden-Württemberg)": "083350000000", + "Reichenau (Konstanz - Baden-Württemberg)": "083350000000", + "Singen (Hohentwiel), Stadt (Konstanz - Baden-Württemberg)": "083350000000", + "Steißlingen (Konstanz - Baden-Württemberg)": "083350000000", + "Volkertshausen (Konstanz - Baden-Württemberg)": "083350000000", + "Rielasingen-Worblingen (Konstanz - Baden-Württemberg)": "083350000000", + "Eigeltingen (Konstanz - Baden-Württemberg)": "083350000000", + "Mühlingen (Konstanz - Baden-Württemberg)": "083350000000", + "Stockach, Stadt (Konstanz - Baden-Württemberg)": "083350000000", + "Hohenfels (Konstanz - Baden-Württemberg)": "083350000000", + "Bodman-Ludwigshafen (Konstanz - Baden-Württemberg)": "083350000000", + "Orsingen-Nenzingen (Konstanz - Baden-Württemberg)": "083350000000", + "Efringen-Kirchen (Lörrach - Baden-Württemberg)": "083360000000", + "Steinen (Lörrach - Baden-Württemberg)": "083360000000", + "Todtnau, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Weil am Rhein, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Grenzach-Wyhlen (Lörrach - Baden-Württemberg)": "083360000000", + "Kleines Wiesental (Lörrach - Baden-Württemberg)": "083360000000", + "Kandern, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Malsburg-Marzell (Lörrach - Baden-Württemberg)": "083360000000", + "Inzlingen (Lörrach - Baden-Württemberg)": "083360000000", + "Lörrach, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Rheinfelden (Baden), Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Schwörstadt (Lörrach - Baden-Württemberg)": "083360000000", + "Bad Bellingen (Lörrach - Baden-Württemberg)": "083360000000", + "Schliengen (Lörrach - Baden-Württemberg)": "083360000000", + "Aitern (Lörrach - Baden-Württemberg)": "083360000000", + "Böllen (Lörrach - Baden-Württemberg)": "083360000000", + "Fröhnd (Lörrach - Baden-Württemberg)": "083360000000", + "Schönau im Schwarzwald, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Schönenberg (Lörrach - Baden-Württemberg)": "083360000000", + "Tunau (Lörrach - Baden-Württemberg)": "083360000000", + "Utzenfeld (Lörrach - Baden-Württemberg)": "083360000000", + "Wembach (Lörrach - Baden-Württemberg)": "083360000000", + "Wieden (Lörrach - Baden-Württemberg)": "083360000000", + "Hasel (Lörrach - Baden-Württemberg)": "083360000000", + "Hausen im Wiesental (Lörrach - Baden-Württemberg)": "083360000000", + "Maulburg (Lörrach - Baden-Württemberg)": "083360000000", + "Schopfheim, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Binzen (Lörrach - Baden-Württemberg)": "083360000000", + "Eimeldingen (Lörrach - Baden-Württemberg)": "083360000000", + "Fischingen (Lörrach - Baden-Württemberg)": "083360000000", + "Rümmingen (Lörrach - Baden-Württemberg)": "083360000000", + "Schallbach (Lörrach - Baden-Württemberg)": "083360000000", + "Wittlingen (Lörrach - Baden-Württemberg)": "083360000000", + "Zell im Wiesental, Stadt (Lörrach - Baden-Württemberg)": "083360000000", + "Häg-Ehrsberg (Lörrach - Baden-Württemberg)": "083360000000", + "Albbruck (Waldshut - Baden-Württemberg)": "083370000000", + "Görwihl (Waldshut - Baden-Württemberg)": "083370000000", + "Klettgau (Waldshut - Baden-Württemberg)": "083370000000", + "Laufenburg (Baden), Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Stühlingen, Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Wehr, Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Bonndorf im Schwarzwald, Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Wutach (Waldshut - Baden-Württemberg)": "083370000000", + "Dettighofen (Waldshut - Baden-Württemberg)": "083370000000", + "Jestetten (Waldshut - Baden-Württemberg)": "083370000000", + "Lottstetten (Waldshut - Baden-Württemberg)": "083370000000", + "Hohentengen am Hochrhein (Waldshut - Baden-Württemberg)": "083370000000", + "Küssaberg (Waldshut - Baden-Württemberg)": "083370000000", + "Grafenhausen (Waldshut - Baden-Württemberg)": "083370000000", + "Ühlingen-Birkendorf (Waldshut - Baden-Württemberg)": "083370000000", + "Herrischried (Waldshut - Baden-Württemberg)": "083370000000", + "Murg (Waldshut - Baden-Württemberg)": "083370000000", + "Rickenbach (Waldshut - Baden-Württemberg)": "083370000000", + "Bad Säckingen, Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Bernau im Schwarzwald (Waldshut - Baden-Württemberg)": "083370000000", + "Dachsberg (Südschwarzwald) (Waldshut - Baden-Württemberg)": "083370000000", + "Häusern (Waldshut - Baden-Württemberg)": "083370000000", + "Höchenschwand (Waldshut - Baden-Württemberg)": "083370000000", + "Ibach (Waldshut - Baden-Württemberg)": "083370000000", + "St. Blasien, Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Todtmoos (Waldshut - Baden-Württemberg)": "083370000000", + "Dogern (Waldshut - Baden-Württemberg)": "083370000000", + "Lauchringen (Waldshut - Baden-Württemberg)": "083370000000", + "Weilheim (Waldshut - Baden-Württemberg)": "083370000000", + "Waldshut-Tiengen, Stadt (Waldshut - Baden-Württemberg)": "083370000000", + "Wutöschingen (Waldshut - Baden-Württemberg)": "083370000000", + "Eggingen (Waldshut - Baden-Württemberg)": "083370000000", + "Dettingen an der Erms (Reutlingen - Baden-Württemberg)": "084150000000", + "Eningen unter Achalm (Reutlingen - Baden-Württemberg)": "084150000000", + "Pfullingen, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Reutlingen, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Trochtelfingen, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Wannweil (Reutlingen - Baden-Württemberg)": "084150000000", + "Sonnenbühl (Reutlingen - Baden-Württemberg)": "084150000000", + "Lichtenstein (Reutlingen - Baden-Württemberg)": "084150000000", + "St. Johann (Reutlingen - Baden-Württemberg)": "084150000000", + "Engstingen (Reutlingen - Baden-Württemberg)": "084150000000", + "Hohenstein (Reutlingen - Baden-Württemberg)": "084150000000", + "Grafenberg (Reutlingen - Baden-Württemberg)": "084150000000", + "Metzingen, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Riederich (Reutlingen - Baden-Württemberg)": "084150000000", + "Gomadingen (Reutlingen - Baden-Württemberg)": "084150000000", + "Mehrstetten (Reutlingen - Baden-Württemberg)": "084150000000", + "Münsingen, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Pliezhausen (Reutlingen - Baden-Württemberg)": "084150000000", + "Walddorfhäslach (Reutlingen - Baden-Württemberg)": "084150000000", + "Grabenstetten (Reutlingen - Baden-Württemberg)": "084150000000", + "Hülben (Reutlingen - Baden-Württemberg)": "084150000000", + "Bad Urach, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Römerstein (Reutlingen - Baden-Württemberg)": "084150000000", + "Hayingen, Stadt (Reutlingen - Baden-Württemberg)": "084150000000", + "Pfronstetten (Reutlingen - Baden-Württemberg)": "084150000000", + "Zwiefalten (Reutlingen - Baden-Württemberg)": "084150000000", + "Gutsbezirk Münsingen, gemeindefreies Gebiet (Reutlingen - Baden-Württemberg)": "084150000000", + "Dettenhausen (Tübingen - Baden-Württemberg)": "084160000000", + "Kirchentellinsfurt (Tübingen - Baden-Württemberg)": "084160000000", + "Kusterdingen (Tübingen - Baden-Württemberg)": "084160000000", + "Tübingen, Universitätsstadt (Tübingen - Baden-Württemberg)": "084160000000", + "Ammerbuch (Tübingen - Baden-Württemberg)": "084160000000", + "Dußlingen (Tübingen - Baden-Württemberg)": "084160000000", + "Gomaringen (Tübingen - Baden-Württemberg)": "084160000000", + "Nehren (Tübingen - Baden-Württemberg)": "084160000000", + "Bodelshausen (Tübingen - Baden-Württemberg)": "084160000000", + "Mössingen, Stadt (Tübingen - Baden-Württemberg)": "084160000000", + "Ofterdingen (Tübingen - Baden-Württemberg)": "084160000000", + "Hirrlingen (Tübingen - Baden-Württemberg)": "084160000000", + "Rottenburg am Neckar, Stadt (Tübingen - Baden-Württemberg)": "084160000000", + "Neustetten (Tübingen - Baden-Württemberg)": "084160000000", + "Starzach (Tübingen - Baden-Württemberg)": "084160000000", + "Burladingen, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Haigerloch, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Rosenfeld, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Bitz (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Albstadt, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Balingen, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Geislingen, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Bisingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Grosselfingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Hechingen, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Jungingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Rangendingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Meßstetten, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Nusplingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Obernheim (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Dautmergen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Dormettingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Dotternhausen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Hausen am Tann (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Ratshausen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Schömberg, Stadt (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Weilen unter den Rinnen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Zimmern unter der Burg (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Straßberg (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Winterlingen (Zollernalbkreis - Baden-Württemberg)": "084170000000", + "Ulm, Universitätsstadt": "084210000000", + "Erbach, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Schelklingen, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Blaustein, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Allmendingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Altheim (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Berghülen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Blaubeuren, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Dietenheim, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Illerrieden (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Balzheim (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Beimerstetten (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Dornstadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Westerstetten (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Ehingen (Donau), Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Griesingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Oberdischingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Öpfingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Hüttisheim (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Schnürpflingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Illerkirchberg (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Staig (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Laichingen, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Merklingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Nellingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Westerheim (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Heroldstatt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Altheim (Alb) (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Asselfingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Ballendorf (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Bernstadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Börslingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Breitingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Holzkirch (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Langenau, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Neenstetten (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Nerenstetten (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Öllingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Rammingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Setzingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Weidenstetten (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Amstetten (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Lonsee (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Emeringen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Emerkingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Grundsheim (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Hausen am Bussen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Lauterach (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Munderkingen, Stadt (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Obermarchtal (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Oberstadion (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Rechtenstein (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Rottenacker (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Untermarchtal (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Unterstadion (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Unterwachingen (Alb-Donau-Kreis - Baden-Württemberg)": "084250000000", + "Schemmerhofen (Biberach - Baden-Württemberg)": "084260000000", + "Alleshausen (Biberach - Baden-Württemberg)": "084260000000", + "Allmannsweiler (Biberach - Baden-Württemberg)": "084260000000", + "Bad Buchau, Stadt (Biberach - Baden-Württemberg)": "084260000000", + "Betzenweiler (Biberach - Baden-Württemberg)": "084260000000", + "Dürnau (Biberach - Baden-Württemberg)": "084260000000", + "Kanzach (Biberach - Baden-Württemberg)": "084260000000", + "Moosburg (Biberach - Baden-Württemberg)": "084260000000", + "Oggelshausen (Biberach - Baden-Württemberg)": "084260000000", + "Seekirch (Biberach - Baden-Württemberg)": "084260000000", + "Tiefenbach (Biberach - Baden-Württemberg)": "084260000000", + "Bad Schussenried, Stadt (Biberach - Baden-Württemberg)": "084260000000", + "Ingoldingen (Biberach - Baden-Württemberg)": "084260000000", + "Attenweiler (Biberach - Baden-Württemberg)": "084260000000", + "Biberach an der Riß, Stadt (Biberach - Baden-Württemberg)": "084260000000", + "Eberhardzell (Biberach - Baden-Württemberg)": "084260000000", + "Hochdorf (Biberach - Baden-Württemberg)": "084260000000", + "Maselheim (Biberach - Baden-Württemberg)": "084260000000", + "Mittelbiberach (Biberach - Baden-Württemberg)": "084260000000", + "Ummendorf (Biberach - Baden-Württemberg)": "084260000000", + "Warthausen (Biberach - Baden-Württemberg)": "084260000000", + "Berkheim (Biberach - Baden-Württemberg)": "084260000000", + "Dettingen an der Iller (Biberach - Baden-Württemberg)": "084260000000", + "Erolzheim (Biberach - Baden-Württemberg)": "084260000000", + "Kirchberg an der Iller (Biberach - Baden-Württemberg)": "084260000000", + "Kirchdorf an der Iller (Biberach - Baden-Württemberg)": "084260000000", + "Achstetten (Biberach - Baden-Württemberg)": "084260000000", + "Burgrieden (Biberach - Baden-Württemberg)": "084260000000", + "Laupheim, Stadt (Biberach - Baden-Württemberg)": "084260000000", + "Mietingen (Biberach - Baden-Württemberg)": "084260000000", + "Erlenmoos (Biberach - Baden-Württemberg)": "084260000000", + "Ochsenhausen, Stadt (Biberach - Baden-Württemberg)": "084260000000", + "Steinhausen an der Rottum (Biberach - Baden-Württemberg)": "084260000000", + "Gutenzell-Hürbel (Biberach - Baden-Württemberg)": "084260000000", + "Altheim (Biberach - Baden-Württemberg)": "084260000000", + "Dürmentingen (Biberach - Baden-Württemberg)": "084260000000", + "Ertingen (Biberach - Baden-Württemberg)": "084260000000", + "Langenenslingen (Biberach - Baden-Württemberg)": "084260000000", + "Riedlingen, Stadt (Biberach - Baden-Württemberg)": "084260000000", + "Unlingen (Biberach - Baden-Württemberg)": "084260000000", + "Uttenweiler (Biberach - Baden-Württemberg)": "084260000000", + "Rot an der Rot (Biberach - Baden-Württemberg)": "084260000000", + "Tannheim (Biberach - Baden-Württemberg)": "084260000000", + "Schwendi (Biberach - Baden-Württemberg)": "084260000000", + "Wain (Biberach - Baden-Württemberg)": "084260000000", + "Meckenbeuren (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Eriskirch (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Kressbronn am Bodensee (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Langenargen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Friedrichshafen, Stadt (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Immenstaad am Bodensee (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Bermatingen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Markdorf, Stadt (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Oberteuringen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Deggenhausertal (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Daisendorf (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Hagnau am Bodensee (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Meersburg, Stadt (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Stetten (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Uhldingen-Mühlhofen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Frickingen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Heiligenberg (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Salem (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Neukirch (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Tettnang, Stadt (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Owingen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Sipplingen (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Überlingen, Stadt (Bodenseekreis - Baden-Württemberg)": "084350000000", + "Aulendorf, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Bad Wurzach, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Isny im Allgäu, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Kißlegg (Ravensburg - Baden-Württemberg)": "084360000000", + "Argenbühl (Ravensburg - Baden-Württemberg)": "084360000000", + "Altshausen (Ravensburg - Baden-Württemberg)": "084360000000", + "Boms (Ravensburg - Baden-Württemberg)": "084360000000", + "Ebenweiler (Ravensburg - Baden-Württemberg)": "084360000000", + "Eichstegen (Ravensburg - Baden-Württemberg)": "084360000000", + "Fleischwangen (Ravensburg - Baden-Württemberg)": "084360000000", + "Guggenhausen (Ravensburg - Baden-Württemberg)": "084360000000", + "Hoßkirch (Ravensburg - Baden-Württemberg)": "084360000000", + "Königseggwald (Ravensburg - Baden-Württemberg)": "084360000000", + "Riedhausen (Ravensburg - Baden-Württemberg)": "084360000000", + "Unterwaldhausen (Ravensburg - Baden-Württemberg)": "084360000000", + "Ebersbach-Musbach (Ravensburg - Baden-Württemberg)": "084360000000", + "Bad Waldsee, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Bergatreute (Ravensburg - Baden-Württemberg)": "084360000000", + "Bodnegg (Ravensburg - Baden-Württemberg)": "084360000000", + "Grünkraut (Ravensburg - Baden-Württemberg)": "084360000000", + "Schlier (Ravensburg - Baden-Württemberg)": "084360000000", + "Waldburg (Ravensburg - Baden-Württemberg)": "084360000000", + "Aichstetten (Ravensburg - Baden-Württemberg)": "084360000000", + "Aitrach (Ravensburg - Baden-Württemberg)": "084360000000", + "Leutkirch im Allgäu, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Baienfurt (Ravensburg - Baden-Württemberg)": "084360000000", + "Baindt (Ravensburg - Baden-Württemberg)": "084360000000", + "Berg (Ravensburg - Baden-Württemberg)": "084360000000", + "Ravensburg, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Weingarten, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Vogt (Ravensburg - Baden-Württemberg)": "084360000000", + "Wolfegg (Ravensburg - Baden-Württemberg)": "084360000000", + "Achberg (Ravensburg - Baden-Württemberg)": "084360000000", + "Amtzell (Ravensburg - Baden-Württemberg)": "084360000000", + "Wangen im Allgäu, Stadt (Ravensburg - Baden-Württemberg)": "084360000000", + "Wilhelmsdorf (Ravensburg - Baden-Württemberg)": "084360000000", + "Horgenzell (Ravensburg - Baden-Württemberg)": "084360000000", + "Wolpertswende (Ravensburg - Baden-Württemberg)": "084360000000", + "Fronreute (Ravensburg - Baden-Württemberg)": "084360000000", + "Ostrach (Sigmaringen - Baden-Württemberg)": "084370000000", + "Gammertingen, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Hettingen, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Neufra (Sigmaringen - Baden-Württemberg)": "084370000000", + "Veringenstadt, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Hohentengen (Sigmaringen - Baden-Württemberg)": "084370000000", + "Mengen, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Scheer, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Leibertingen (Sigmaringen - Baden-Württemberg)": "084370000000", + "Meßkirch, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Sauldorf (Sigmaringen - Baden-Württemberg)": "084370000000", + "Illmensee (Sigmaringen - Baden-Württemberg)": "084370000000", + "Pfullendorf, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Wald (Sigmaringen - Baden-Württemberg)": "084370000000", + "Herdwangen-Schönach (Sigmaringen - Baden-Württemberg)": "084370000000", + "Herbertingen (Sigmaringen - Baden-Württemberg)": "084370000000", + "Bad Saulgau, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Beuron (Sigmaringen - Baden-Württemberg)": "084370000000", + "Bingen (Sigmaringen - Baden-Württemberg)": "084370000000", + "Inzigkofen (Sigmaringen - Baden-Württemberg)": "084370000000", + "Krauchenwies (Sigmaringen - Baden-Württemberg)": "084370000000", + "Sigmaringen, Stadt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Sigmaringendorf (Sigmaringen - Baden-Württemberg)": "084370000000", + "Schwenningen (Sigmaringen - Baden-Württemberg)": "084370000000", + "Stetten am kalten Markt (Sigmaringen - Baden-Württemberg)": "084370000000", + "Ingolstadt": "091610000000", + "München, Landeshauptstadt": "091620000000", + "Rosenheim": "091630000000", + "Altötting, St (Altötting - Bayern)": "091710000000", + "Burghausen, St (Altötting - Bayern)": "091710000000", + "Burgkirchen a.d.Alz (Altötting - Bayern)": "091710000000", + "Garching a.d.Alz (Altötting - Bayern)": "091710000000", + "Haiming (Altötting - Bayern)": "091710000000", + "Neuötting, St (Altötting - Bayern)": "091710000000", + "Pleiskirchen (Altötting - Bayern)": "091710000000", + "Teising (Altötting - Bayern)": "091710000000", + "Töging a.Inn, St (Altötting - Bayern)": "091710000000", + "Tüßling, M (Altötting - Bayern)": "091710000000", + "Winhöring (Altötting - Bayern)": "091710000000", + "Emmerting (Altötting - Bayern)": "091710000000", + "Mehring (Altötting - Bayern)": "091710000000", + "Feichten a.d.Alz (Altötting - Bayern)": "091710000000", + "Halsbach (Altötting - Bayern)": "091710000000", + "Kirchweidach (Altötting - Bayern)": "091710000000", + "Tyrlaching (Altötting - Bayern)": "091710000000", + "Marktl, M (Altötting - Bayern)": "091710000000", + "Stammham (Altötting - Bayern)": "091710000000", + "Erlbach (Altötting - Bayern)": "091710000000", + "Perach (Altötting - Bayern)": "091710000000", + "Reischach (Altötting - Bayern)": "091710000000", + "Kastl (Altötting - Bayern)": "091710000000", + "Unterneukirchen (Altötting - Bayern)": "091710000000", + "Ainring (Berchtesgadener Land - Bayern)": "091720000000", + "Anger (Berchtesgadener Land - Bayern)": "091720000000", + "Bad Reichenhall, GKSt (Berchtesgadener Land - Bayern)": "091720000000", + "Bayerisch Gmain (Berchtesgadener Land - Bayern)": "091720000000", + "Berchtesgaden, M (Berchtesgadener Land - Bayern)": "091720000000", + "Bischofswiesen (Berchtesgadener Land - Bayern)": "091720000000", + "Freilassing, St (Berchtesgadener Land - Bayern)": "091720000000", + "Laufen, St (Berchtesgadener Land - Bayern)": "091720000000", + "Marktschellenberg, M (Berchtesgadener Land - Bayern)": "091720000000", + "Piding (Berchtesgadener Land - Bayern)": "091720000000", + "Ramsau b.Berchtesgaden (Berchtesgadener Land - Bayern)": "091720000000", + "Saaldorf-Surheim (Berchtesgadener Land - Bayern)": "091720000000", + "Schneizlreuth (Berchtesgadener Land - Bayern)": "091720000000", + "Schönau a.Königssee (Berchtesgadener Land - Bayern)": "091720000000", + "Teisendorf, M (Berchtesgadener Land - Bayern)": "091720000000", + "Eck (Berchtesgadener Land - Bayern)": "091720000000", + "Schellenberger Forst (Berchtesgadener Land - Bayern)": "091720000000", + "Bad Heilbrunn (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Bad Tölz, St (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Dietramszell (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Egling (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Eurasburg (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Gaißach (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Geretsried, St (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Icking (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Jachenau (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Königsdorf (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Lenggries (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Münsing (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Wackersberg (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Wolfratshausen, St (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Benediktbeuern (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Bichl (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Kochel a.See (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Schlehdorf (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Greiling (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Reichersbeuern (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Sachsenkam (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Pupplinger Au (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Wolfratshauser Forst (Bad Tölz-Wolfratshausen - Bayern)": "091730000000", + "Altomünster, M (Dachau - Bayern)": "091740000000", + "Bergkirchen (Dachau - Bayern)": "091740000000", + "Dachau, GKSt (Dachau - Bayern)": "091740000000", + "Erdweg (Dachau - Bayern)": "091740000000", + "Haimhausen (Dachau - Bayern)": "091740000000", + "Hebertshausen (Dachau - Bayern)": "091740000000", + "Karlsfeld (Dachau - Bayern)": "091740000000", + "Markt Indersdorf, M (Dachau - Bayern)": "091740000000", + "Odelzhausen (Dachau - Bayern)": "091740000000", + "Petershausen (Dachau - Bayern)": "091740000000", + "Pfaffenhofen a.d.Glonn (Dachau - Bayern)": "091740000000", + "Röhrmoos (Dachau - Bayern)": "091740000000", + "Schwabhausen (Dachau - Bayern)": "091740000000", + "Sulzemoos (Dachau - Bayern)": "091740000000", + "Hilgertshausen-Tandern (Dachau - Bayern)": "091740000000", + "Vierkirchen (Dachau - Bayern)": "091740000000", + "Weichs (Dachau - Bayern)": "091740000000", + "Anzing (Ebersberg - Bayern)": "091750000000", + "Ebersberg, St (Ebersberg - Bayern)": "091750000000", + "Forstinning (Ebersberg - Bayern)": "091750000000", + "Grafing b.München, St (Ebersberg - Bayern)": "091750000000", + "Hohenlinden (Ebersberg - Bayern)": "091750000000", + "Kirchseeon, M (Ebersberg - Bayern)": "091750000000", + "Markt Schwaben, M (Ebersberg - Bayern)": "091750000000", + "Vaterstetten (Ebersberg - Bayern)": "091750000000", + "Pliening (Ebersberg - Bayern)": "091750000000", + "Poing (Ebersberg - Bayern)": "091750000000", + "Steinhöring (Ebersberg - Bayern)": "091750000000", + "Zorneding (Ebersberg - Bayern)": "091750000000", + "Aßling (Ebersberg - Bayern)": "091750000000", + "Frauenneuharting (Ebersberg - Bayern)": "091750000000", + "Emmering (Ebersberg - Bayern)": "091750000000", + "Baiern (Ebersberg - Bayern)": "091750000000", + "Bruck (Ebersberg - Bayern)": "091750000000", + "Egmating (Ebersberg - Bayern)": "091750000000", + "Glonn, M (Ebersberg - Bayern)": "091750000000", + "Moosach (Ebersberg - Bayern)": "091750000000", + "Oberpframmern (Ebersberg - Bayern)": "091750000000", + "Anzinger Forst (Ebersberg - Bayern)": "091750000000", + "Ebersberger Forst (Ebersberg - Bayern)": "091750000000", + "Eglhartinger Forst (Ebersberg - Bayern)": "091750000000", + "Altmannstein, M (Eichstätt - Bayern)": "091760000000", + "Beilngries, St (Eichstätt - Bayern)": "091760000000", + "Buxheim (Eichstätt - Bayern)": "091760000000", + "Denkendorf (Eichstätt - Bayern)": "091760000000", + "Dollnstein, M (Eichstätt - Bayern)": "091760000000", + "Eichstätt, GKSt (Eichstätt - Bayern)": "091760000000", + "Gaimersheim, M (Eichstätt - Bayern)": "091760000000", + "Großmehring (Eichstätt - Bayern)": "091760000000", + "Hepberg (Eichstätt - Bayern)": "091760000000", + "Hitzhofen (Eichstätt - Bayern)": "091760000000", + "Kinding, M (Eichstätt - Bayern)": "091760000000", + "Kipfenberg, M (Eichstätt - Bayern)": "091760000000", + "Kösching, M (Eichstätt - Bayern)": "091760000000", + "Lenting (Eichstätt - Bayern)": "091760000000", + "Mörnsheim, M (Eichstätt - Bayern)": "091760000000", + "Stammham (Eichstätt - Bayern)": "091760000000", + "Titting, M (Eichstätt - Bayern)": "091760000000", + "Wellheim, M (Eichstätt - Bayern)": "091760000000", + "Wettstetten (Eichstätt - Bayern)": "091760000000", + "Pollenfeld (Eichstätt - Bayern)": "091760000000", + "Schernfeld (Eichstätt - Bayern)": "091760000000", + "Walting (Eichstätt - Bayern)": "091760000000", + "Böhmfeld (Eichstätt - Bayern)": "091760000000", + "Eitensheim (Eichstätt - Bayern)": "091760000000", + "Adelschlag (Eichstätt - Bayern)": "091760000000", + "Egweil (Eichstätt - Bayern)": "091760000000", + "Nassenfels, M (Eichstätt - Bayern)": "091760000000", + "Mindelstetten (Eichstätt - Bayern)": "091760000000", + "Oberdolling (Eichstätt - Bayern)": "091760000000", + "Pförring, M (Eichstätt - Bayern)": "091760000000", + "Haunstetter Forst (Eichstätt - Bayern)": "091760000000", + "Bockhorn (Erding - Bayern)": "091770000000", + "Dorfen, St (Erding - Bayern)": "091770000000", + "Erding, GKSt (Erding - Bayern)": "091770000000", + "Finsing (Erding - Bayern)": "091770000000", + "Forstern (Erding - Bayern)": "091770000000", + "Fraunberg (Erding - Bayern)": "091770000000", + "Isen, M (Erding - Bayern)": "091770000000", + "Lengdorf (Erding - Bayern)": "091770000000", + "Moosinning (Erding - Bayern)": "091770000000", + "Sankt Wolfgang (Erding - Bayern)": "091770000000", + "Taufkirchen (Vils) (Erding - Bayern)": "091770000000", + "Buch a.Buchrain (Erding - Bayern)": "091770000000", + "Pastetten (Erding - Bayern)": "091770000000", + "Walpertskirchen (Erding - Bayern)": "091770000000", + "Wörth (Erding - Bayern)": "091770000000", + "Eitting (Erding - Bayern)": "091770000000", + "Oberding (Erding - Bayern)": "091770000000", + "Neuching (Erding - Bayern)": "091770000000", + "Ottenhofen (Erding - Bayern)": "091770000000", + "Hohenpolding (Erding - Bayern)": "091770000000", + "Inning a.Holz (Erding - Bayern)": "091770000000", + "Kirchberg (Erding - Bayern)": "091770000000", + "Steinkirchen (Erding - Bayern)": "091770000000", + "Berglern (Erding - Bayern)": "091770000000", + "Langenpreising (Erding - Bayern)": "091770000000", + "Wartenberg, M (Erding - Bayern)": "091770000000", + "Au i.d.Hallertau, M (Freising - Bayern)": "091780000000", + "Eching (Freising - Bayern)": "091780000000", + "Rudelzhausen (Freising - Bayern)": "091780000000", + "Fahrenzhausen (Freising - Bayern)": "091780000000", + "Freising, GKSt (Freising - Bayern)": "091780000000", + "Hallbergmoos (Freising - Bayern)": "091780000000", + "Hohenkammer (Freising - Bayern)": "091780000000", + "Kirchdorf a.d.Amper (Freising - Bayern)": "091780000000", + "Kranzberg (Freising - Bayern)": "091780000000", + "Langenbach (Freising - Bayern)": "091780000000", + "Marzling (Freising - Bayern)": "091780000000", + "Moosburg a.d.Isar, St (Freising - Bayern)": "091780000000", + "Nandlstadt, M (Freising - Bayern)": "091780000000", + "Neufahrn b.Freising (Freising - Bayern)": "091780000000", + "Allershausen (Freising - Bayern)": "091780000000", + "Paunzhausen (Freising - Bayern)": "091780000000", + "Gammelsdorf (Freising - Bayern)": "091780000000", + "Hörgertshausen (Freising - Bayern)": "091780000000", + "Mauern (Freising - Bayern)": "091780000000", + "Wang (Freising - Bayern)": "091780000000", + "Attenkirchen (Freising - Bayern)": "091780000000", + "Haag a.d.Amper (Freising - Bayern)": "091780000000", + "Wolfersdorf (Freising - Bayern)": "091780000000", + "Zolling (Freising - Bayern)": "091780000000", + "Alling (Fürstenfeldbruck - Bayern)": "091790000000", + "Egenhofen (Fürstenfeldbruck - Bayern)": "091790000000", + "Eichenau (Fürstenfeldbruck - Bayern)": "091790000000", + "Emmering (Fürstenfeldbruck - Bayern)": "091790000000", + "Fürstenfeldbruck, GKSt (Fürstenfeldbruck - Bayern)": "091790000000", + "Germering, GKSt (Fürstenfeldbruck - Bayern)": "091790000000", + "Gröbenzell (Fürstenfeldbruck - Bayern)": "091790000000", + "Maisach (Fürstenfeldbruck - Bayern)": "091790000000", + "Moorenweis (Fürstenfeldbruck - Bayern)": "091790000000", + "Olching, St (Fürstenfeldbruck - Bayern)": "091790000000", + "Puchheim, St (Fürstenfeldbruck - Bayern)": "091790000000", + "Türkenfeld (Fürstenfeldbruck - Bayern)": "091790000000", + "Adelshofen (Fürstenfeldbruck - Bayern)": "091790000000", + "Althegnenberg (Fürstenfeldbruck - Bayern)": "091790000000", + "Hattenhofen (Fürstenfeldbruck - Bayern)": "091790000000", + "Jesenwang (Fürstenfeldbruck - Bayern)": "091790000000", + "Landsberied (Fürstenfeldbruck - Bayern)": "091790000000", + "Mammendorf (Fürstenfeldbruck - Bayern)": "091790000000", + "Mittelstetten (Fürstenfeldbruck - Bayern)": "091790000000", + "Oberschweinbach (Fürstenfeldbruck - Bayern)": "091790000000", + "Grafrath (Fürstenfeldbruck - Bayern)": "091790000000", + "Kottgeisering (Fürstenfeldbruck - Bayern)": "091790000000", + "Schöngeising (Fürstenfeldbruck - Bayern)": "091790000000", + "Bad Kohlgrub (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Farchant (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Garmisch-Partenkirchen, M (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Grainau (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Krün (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Mittenwald, M (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Murnau a.Staffelsee, M (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Oberammergau (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Oberau (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Uffing a.Staffelsee (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Wallgau (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Bad Bayersoien (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Saulgrub (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Ettal (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Unterammergau (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Eschenlohe (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Großweil (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Ohlstadt (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Schwaigen (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Riegsee (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Seehausen a.Staffelsee (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Spatzenhausen (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Ettaler Forst (Garmisch-Partenkirchen - Bayern)": "091800000000", + "Denklingen (Landsberg am Lech - Bayern)": "091810000000", + "Dießen am Ammersee, M (Landsberg am Lech - Bayern)": "091810000000", + "Egling a.d.Paar (Landsberg am Lech - Bayern)": "091810000000", + "Geltendorf (Landsberg am Lech - Bayern)": "091810000000", + "Kaufering, M (Landsberg am Lech - Bayern)": "091810000000", + "Landsberg am Lech, GKSt (Landsberg am Lech - Bayern)": "091810000000", + "Penzing (Landsberg am Lech - Bayern)": "091810000000", + "Utting am Ammersee (Landsberg am Lech - Bayern)": "091810000000", + "Weil (Landsberg am Lech - Bayern)": "091810000000", + "Fuchstal (Landsberg am Lech - Bayern)": "091810000000", + "Unterdießen (Landsberg am Lech - Bayern)": "091810000000", + "Hurlach (Landsberg am Lech - Bayern)": "091810000000", + "Igling (Landsberg am Lech - Bayern)": "091810000000", + "Obermeitingen (Landsberg am Lech - Bayern)": "091810000000", + "Prittriching (Landsberg am Lech - Bayern)": "091810000000", + "Scheuring (Landsberg am Lech - Bayern)": "091810000000", + "Hofstetten (Landsberg am Lech - Bayern)": "091810000000", + "Schwifting (Landsberg am Lech - Bayern)": "091810000000", + "Pürgen (Landsberg am Lech - Bayern)": "091810000000", + "Apfeldorf (Landsberg am Lech - Bayern)": "091810000000", + "Kinsau (Landsberg am Lech - Bayern)": "091810000000", + "Vilgertshofen (Landsberg am Lech - Bayern)": "091810000000", + "Reichling (Landsberg am Lech - Bayern)": "091810000000", + "Rott (Landsberg am Lech - Bayern)": "091810000000", + "Thaining (Landsberg am Lech - Bayern)": "091810000000", + "Eching am Ammersee (Landsberg am Lech - Bayern)": "091810000000", + "Greifenberg (Landsberg am Lech - Bayern)": "091810000000", + "Schondorf am Ammersee (Landsberg am Lech - Bayern)": "091810000000", + "Eresing (Landsberg am Lech - Bayern)": "091810000000", + "Finning (Landsberg am Lech - Bayern)": "091810000000", + "Windach (Landsberg am Lech - Bayern)": "091810000000", + "Ammersee (Landsberg am Lech - Bayern)": "091810000000", + "Bad Wiessee (Miesbach - Bayern)": "091820000000", + "Bayrischzell (Miesbach - Bayern)": "091820000000", + "Fischbachau (Miesbach - Bayern)": "091820000000", + "Gmund a.Tegernsee (Miesbach - Bayern)": "091820000000", + "Hausham (Miesbach - Bayern)": "091820000000", + "Holzkirchen, M (Miesbach - Bayern)": "091820000000", + "Irschenberg (Miesbach - Bayern)": "091820000000", + "Kreuth (Miesbach - Bayern)": "091820000000", + "Miesbach, St (Miesbach - Bayern)": "091820000000", + "Otterfing (Miesbach - Bayern)": "091820000000", + "Rottach-Egern (Miesbach - Bayern)": "091820000000", + "Schliersee, M (Miesbach - Bayern)": "091820000000", + "Tegernsee, St (Miesbach - Bayern)": "091820000000", + "Valley (Miesbach - Bayern)": "091820000000", + "Waakirchen (Miesbach - Bayern)": "091820000000", + "Warngau (Miesbach - Bayern)": "091820000000", + "Weyarn (Miesbach - Bayern)": "091820000000", + "Ampfing (Mühldorf am Inn - Bayern)": "091830000000", + "Aschau a.Inn (Mühldorf am Inn - Bayern)": "091830000000", + "Buchbach, M (Mühldorf am Inn - Bayern)": "091830000000", + "Haag i.OB, M (Mühldorf am Inn - Bayern)": "091830000000", + "Mettenheim (Mühldorf am Inn - Bayern)": "091830000000", + "Mühldorf a.Inn, St (Mühldorf am Inn - Bayern)": "091830000000", + "Obertaufkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Schwindegg (Mühldorf am Inn - Bayern)": "091830000000", + "Waldkraiburg, St (Mühldorf am Inn - Bayern)": "091830000000", + "Heldenstein (Mühldorf am Inn - Bayern)": "091830000000", + "Rattenkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Gars a.Inn, M (Mühldorf am Inn - Bayern)": "091830000000", + "Unterreit (Mühldorf am Inn - Bayern)": "091830000000", + "Kirchdorf (Mühldorf am Inn - Bayern)": "091830000000", + "Reichertsheim (Mühldorf am Inn - Bayern)": "091830000000", + "Jettenbach (Mühldorf am Inn - Bayern)": "091830000000", + "Kraiburg a.Inn, M (Mühldorf am Inn - Bayern)": "091830000000", + "Taufkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Egglkofen (Mühldorf am Inn - Bayern)": "091830000000", + "Neumarkt-Sankt Veit, St (Mühldorf am Inn - Bayern)": "091830000000", + "Lohkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Oberbergkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Schönberg (Mühldorf am Inn - Bayern)": "091830000000", + "Zangberg (Mühldorf am Inn - Bayern)": "091830000000", + "Oberneukirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Polling (Mühldorf am Inn - Bayern)": "091830000000", + "Erharting (Mühldorf am Inn - Bayern)": "091830000000", + "Niederbergkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Niedertaufkirchen (Mühldorf am Inn - Bayern)": "091830000000", + "Maitenbeth (Mühldorf am Inn - Bayern)": "091830000000", + "Rechtmehring (Mühldorf am Inn - Bayern)": "091830000000", + "Mühldorfer Hart (Mühldorf am Inn - Bayern)": "091830000000", + "Aschheim (München - Bayern)": "091840000000", + "Baierbrunn (München - Bayern)": "091840000000", + "Brunnthal (München - Bayern)": "091840000000", + "Feldkirchen (München - Bayern)": "091840000000", + "Garching b.München, St (München - Bayern)": "091840000000", + "Gräfelfing (München - Bayern)": "091840000000", + "Grasbrunn (München - Bayern)": "091840000000", + "Grünwald (München - Bayern)": "091840000000", + "Haar (München - Bayern)": "091840000000", + "Höhenkirchen-Siegertsbrunn (München - Bayern)": "091840000000", + "Hohenbrunn (München - Bayern)": "091840000000", + "Ismaning (München - Bayern)": "091840000000", + "Kirchheim b.München (München - Bayern)": "091840000000", + "Neuried (München - Bayern)": "091840000000", + "Oberhaching (München - Bayern)": "091840000000", + "Oberschleißheim (München - Bayern)": "091840000000", + "Ottobrunn (München - Bayern)": "091840000000", + "Aying (München - Bayern)": "091840000000", + "Planegg (München - Bayern)": "091840000000", + "Pullach i.Isartal (München - Bayern)": "091840000000", + "Putzbrunn (München - Bayern)": "091840000000", + "Sauerlach (München - Bayern)": "091840000000", + "Schäftlarn (München - Bayern)": "091840000000", + "Straßlach-Dingharting (München - Bayern)": "091840000000", + "Taufkirchen (München - Bayern)": "091840000000", + "Neubiberg (München - Bayern)": "091840000000", + "Unterföhring (München - Bayern)": "091840000000", + "Unterhaching (München - Bayern)": "091840000000", + "Unterschleißheim, St (München - Bayern)": "091840000000", + "Forstenrieder Park (München - Bayern)": "091840000000", + "Grünwalder Forst (München - Bayern)": "091840000000", + "Perlacher Forst (München - Bayern)": "091840000000", + "Aresing (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Burgheim, M (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Ehekirchen (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Karlshuld (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Karlskron (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Neuburg a.d.Donau, GKSt (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Oberhausen (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Rennertshofen, M (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Schrobenhausen, St (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Königsmoos (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Weichering (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Bergheim (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Rohrenfels (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Berg im Gau (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Brunnen (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Gachenbach (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Langenmosen (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Waidhofen (Neuburg-Schrobenhausen - Bayern)": "091850000000", + "Baar-Ebenhausen (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Gerolsbach (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Hohenwart, M (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Jetzendorf (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Manching, M (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Münchsmünster (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Pfaffenhofen a.d.Ilm, St (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Reichertshausen (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Rohrbach (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Scheyern (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Schweitenkirchen (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Vohburg a.d.Donau, St (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Wolnzach, M (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Ernsgaden (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Geisenfeld, St (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Hettenshausen (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Ilmmünster (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Pörnbach (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Reichertshofen, M (Pfaffenhofen an der Ilm - Bayern)": "091860000000", + "Amerang (Rosenheim - Bayern)": "091870000000", + "Aschau i.Chiemgau (Rosenheim - Bayern)": "091870000000", + "Babensham (Rosenheim - Bayern)": "091870000000", + "Bad Aibling, St (Rosenheim - Bayern)": "091870000000", + "Bernau a.Chiemsee (Rosenheim - Bayern)": "091870000000", + "Brannenburg (Rosenheim - Bayern)": "091870000000", + "Bruckmühl, M (Rosenheim - Bayern)": "091870000000", + "Edling (Rosenheim - Bayern)": "091870000000", + "Eggstätt (Rosenheim - Bayern)": "091870000000", + "Eiselfing (Rosenheim - Bayern)": "091870000000", + "Bad Endorf, M (Rosenheim - Bayern)": "091870000000", + "Bad Feilnbach (Rosenheim - Bayern)": "091870000000", + "Feldkirchen-Westerham (Rosenheim - Bayern)": "091870000000", + "Flintsbach a.Inn (Rosenheim - Bayern)": "091870000000", + "Frasdorf (Rosenheim - Bayern)": "091870000000", + "Griesstätt (Rosenheim - Bayern)": "091870000000", + "Großkarolinenfeld (Rosenheim - Bayern)": "091870000000", + "Schechen (Rosenheim - Bayern)": "091870000000", + "Kiefersfelden (Rosenheim - Bayern)": "091870000000", + "Kolbermoor, St (Rosenheim - Bayern)": "091870000000", + "Neubeuern, M (Rosenheim - Bayern)": "091870000000", + "Nußdorf a.Inn (Rosenheim - Bayern)": "091870000000", + "Oberaudorf (Rosenheim - Bayern)": "091870000000", + "Prien a.Chiemsee, M (Rosenheim - Bayern)": "091870000000", + "Prutting (Rosenheim - Bayern)": "091870000000", + "Raubling (Rosenheim - Bayern)": "091870000000", + "Riedering (Rosenheim - Bayern)": "091870000000", + "Rimsting (Rosenheim - Bayern)": "091870000000", + "Rohrdorf (Rosenheim - Bayern)": "091870000000", + "Samerberg (Rosenheim - Bayern)": "091870000000", + "Söchtenau (Rosenheim - Bayern)": "091870000000", + "Soyen (Rosenheim - Bayern)": "091870000000", + "Stephanskirchen (Rosenheim - Bayern)": "091870000000", + "Tuntenhausen (Rosenheim - Bayern)": "091870000000", + "Vogtareuth (Rosenheim - Bayern)": "091870000000", + "Wasserburg a.Inn, St (Rosenheim - Bayern)": "091870000000", + "Breitbrunn a.Chiemsee (Rosenheim - Bayern)": "091870000000", + "Chiemsee (Rosenheim - Bayern)": "091870000000", + "Gstadt a.Chiemsee (Rosenheim - Bayern)": "091870000000", + "Halfing (Rosenheim - Bayern)": "091870000000", + "Höslwang (Rosenheim - Bayern)": "091870000000", + "Schonstett (Rosenheim - Bayern)": "091870000000", + "Ramerberg (Rosenheim - Bayern)": "091870000000", + "Rott a.Inn (Rosenheim - Bayern)": "091870000000", + "Pfaffing (Rosenheim - Bayern)": "091870000000", + "Albaching (Rosenheim - Bayern)": "091870000000", + "Rotter Forst-Nord (Rosenheim - Bayern)": "091870000000", + "Rotter Forst-Süd (Rosenheim - Bayern)": "091870000000", + "Berg (Starnberg - Bayern)": "091880000000", + "Andechs (Starnberg - Bayern)": "091880000000", + "Feldafing (Starnberg - Bayern)": "091880000000", + "Gauting (Starnberg - Bayern)": "091880000000", + "Gilching (Starnberg - Bayern)": "091880000000", + "Herrsching a.Ammersee (Starnberg - Bayern)": "091880000000", + "Inning a.Ammersee (Starnberg - Bayern)": "091880000000", + "Krailling (Starnberg - Bayern)": "091880000000", + "Seefeld (Starnberg - Bayern)": "091880000000", + "Pöcking (Starnberg - Bayern)": "091880000000", + "Starnberg, St (Starnberg - Bayern)": "091880000000", + "Tutzing (Starnberg - Bayern)": "091880000000", + "Weßling (Starnberg - Bayern)": "091880000000", + "Wörthsee (Starnberg - Bayern)": "091880000000", + "Starnberger See (Starnberg - Bayern)": "091880000000", + "Altenmarkt a.d.Alz (Traunstein - Bayern)": "091890000000", + "Chieming (Traunstein - Bayern)": "091890000000", + "Engelsberg (Traunstein - Bayern)": "091890000000", + "Fridolfing (Traunstein - Bayern)": "091890000000", + "Grabenstätt (Traunstein - Bayern)": "091890000000", + "Grassau, M (Traunstein - Bayern)": "091890000000", + "Inzell (Traunstein - Bayern)": "091890000000", + "Kirchanschöring (Traunstein - Bayern)": "091890000000", + "Nußdorf (Traunstein - Bayern)": "091890000000", + "Palling (Traunstein - Bayern)": "091890000000", + "Petting (Traunstein - Bayern)": "091890000000", + "Reit im Winkl (Traunstein - Bayern)": "091890000000", + "Ruhpolding (Traunstein - Bayern)": "091890000000", + "Schleching (Traunstein - Bayern)": "091890000000", + "Schnaitsee (Traunstein - Bayern)": "091890000000", + "Seeon-Seebruck (Traunstein - Bayern)": "091890000000", + "Siegsdorf (Traunstein - Bayern)": "091890000000", + "Surberg (Traunstein - Bayern)": "091890000000", + "Tacherting (Traunstein - Bayern)": "091890000000", + "Tittmoning, St (Traunstein - Bayern)": "091890000000", + "Traunreut, St (Traunstein - Bayern)": "091890000000", + "Traunstein, GKSt (Traunstein - Bayern)": "091890000000", + "Trostberg, St (Traunstein - Bayern)": "091890000000", + "Übersee (Traunstein - Bayern)": "091890000000", + "Unterwössen (Traunstein - Bayern)": "091890000000", + "Bergen (Traunstein - Bayern)": "091890000000", + "Vachendorf (Traunstein - Bayern)": "091890000000", + "Marquartstein (Traunstein - Bayern)": "091890000000", + "Staudach-Egerndach (Traunstein - Bayern)": "091890000000", + "Kienberg (Traunstein - Bayern)": "091890000000", + "Obing (Traunstein - Bayern)": "091890000000", + "Pittenhart (Traunstein - Bayern)": "091890000000", + "Taching a.See (Traunstein - Bayern)": "091890000000", + "Waging a.See, M (Traunstein - Bayern)": "091890000000", + "Wonneberg (Traunstein - Bayern)": "091890000000", + "Chiemsee (See) (Traunstein - Bayern)": "091890000000", + "Waginger See (Traunstein - Bayern)": "091890000000", + "Bernried am Starnberger See (Weilheim-Schongau - Bayern)": "091900000000", + "Hohenpeißenberg (Weilheim-Schongau - Bayern)": "091900000000", + "Pähl (Weilheim-Schongau - Bayern)": "091900000000", + "Peißenberg, M (Weilheim-Schongau - Bayern)": "091900000000", + "Peiting, M (Weilheim-Schongau - Bayern)": "091900000000", + "Penzberg, St (Weilheim-Schongau - Bayern)": "091900000000", + "Polling (Weilheim-Schongau - Bayern)": "091900000000", + "Raisting (Weilheim-Schongau - Bayern)": "091900000000", + "Schongau, St (Weilheim-Schongau - Bayern)": "091900000000", + "Weilheim i.OB, St (Weilheim-Schongau - Bayern)": "091900000000", + "Wessobrunn (Weilheim-Schongau - Bayern)": "091900000000", + "Wielenbach (Weilheim-Schongau - Bayern)": "091900000000", + "Altenstadt (Weilheim-Schongau - Bayern)": "091900000000", + "Hohenfurch (Weilheim-Schongau - Bayern)": "091900000000", + "Ingenried (Weilheim-Schongau - Bayern)": "091900000000", + "Schwabbruck (Weilheim-Schongau - Bayern)": "091900000000", + "Schwabsoien (Weilheim-Schongau - Bayern)": "091900000000", + "Bernbeuren (Weilheim-Schongau - Bayern)": "091900000000", + "Burggen (Weilheim-Schongau - Bayern)": "091900000000", + "Antdorf (Weilheim-Schongau - Bayern)": "091900000000", + "Habach (Weilheim-Schongau - Bayern)": "091900000000", + "Obersöchering (Weilheim-Schongau - Bayern)": "091900000000", + "Sindelsdorf (Weilheim-Schongau - Bayern)": "091900000000", + "Eberfing (Weilheim-Schongau - Bayern)": "091900000000", + "Eglfing (Weilheim-Schongau - Bayern)": "091900000000", + "Huglfing (Weilheim-Schongau - Bayern)": "091900000000", + "Oberhausen (Weilheim-Schongau - Bayern)": "091900000000", + "Böbing (Weilheim-Schongau - Bayern)": "091900000000", + "Rottenbuch (Weilheim-Schongau - Bayern)": "091900000000", + "Iffeldorf (Weilheim-Schongau - Bayern)": "091900000000", + "Seeshaupt (Weilheim-Schongau - Bayern)": "091900000000", + "Prem (Weilheim-Schongau - Bayern)": "091900000000", + "Steingaden (Weilheim-Schongau - Bayern)": "091900000000", + "Wildsteig (Weilheim-Schongau - Bayern)": "091900000000", + "Landshut": "092610000000", + "Passau": "092620000000", + "Straubing": "092630000000", + "Aholming (Deggendorf - Bayern)": "092710000000", + "Auerbach (Deggendorf - Bayern)": "092710000000", + "Bernried (Deggendorf - Bayern)": "092710000000", + "Deggendorf, GKSt (Deggendorf - Bayern)": "092710000000", + "Grafling (Deggendorf - Bayern)": "092710000000", + "Hengersberg, M (Deggendorf - Bayern)": "092710000000", + "Iggensbach (Deggendorf - Bayern)": "092710000000", + "Künzing (Deggendorf - Bayern)": "092710000000", + "Metten, M (Deggendorf - Bayern)": "092710000000", + "Niederalteich (Deggendorf - Bayern)": "092710000000", + "Offenberg (Deggendorf - Bayern)": "092710000000", + "Osterhofen, St (Deggendorf - Bayern)": "092710000000", + "Plattling, St (Deggendorf - Bayern)": "092710000000", + "Stephansposching (Deggendorf - Bayern)": "092710000000", + "Winzer, M (Deggendorf - Bayern)": "092710000000", + "Grattersdorf (Deggendorf - Bayern)": "092710000000", + "Hunding (Deggendorf - Bayern)": "092710000000", + "Lalling (Deggendorf - Bayern)": "092710000000", + "Schaufling (Deggendorf - Bayern)": "092710000000", + "Oberpöring (Deggendorf - Bayern)": "092710000000", + "Otzing (Deggendorf - Bayern)": "092710000000", + "Wallerfing (Deggendorf - Bayern)": "092710000000", + "Buchhofen (Deggendorf - Bayern)": "092710000000", + "Moos (Deggendorf - Bayern)": "092710000000", + "Außernzell (Deggendorf - Bayern)": "092710000000", + "Schöllnach, M (Deggendorf - Bayern)": "092710000000", + "Freyung, St (Freyung-Grafenau - Bayern)": "092720000000", + "Grafenau, St (Freyung-Grafenau - Bayern)": "092720000000", + "Grainet (Freyung-Grafenau - Bayern)": "092720000000", + "Haidmühle (Freyung-Grafenau - Bayern)": "092720000000", + "Hohenau (Freyung-Grafenau - Bayern)": "092720000000", + "Jandelsbrunn (Freyung-Grafenau - Bayern)": "092720000000", + "Mauth (Freyung-Grafenau - Bayern)": "092720000000", + "Neureichenau (Freyung-Grafenau - Bayern)": "092720000000", + "Ringelai (Freyung-Grafenau - Bayern)": "092720000000", + "Röhrnbach, M (Freyung-Grafenau - Bayern)": "092720000000", + "Saldenburg (Freyung-Grafenau - Bayern)": "092720000000", + "Sankt Oswald-Riedlhütte (Freyung-Grafenau - Bayern)": "092720000000", + "Neuschönau (Freyung-Grafenau - Bayern)": "092720000000", + "Spiegelau (Freyung-Grafenau - Bayern)": "092720000000", + "Waldkirchen, St (Freyung-Grafenau - Bayern)": "092720000000", + "Eppenschlag (Freyung-Grafenau - Bayern)": "092720000000", + "Innernzell (Freyung-Grafenau - Bayern)": "092720000000", + "Schöfweg (Freyung-Grafenau - Bayern)": "092720000000", + "Schönberg, M (Freyung-Grafenau - Bayern)": "092720000000", + "Hinterschmiding (Freyung-Grafenau - Bayern)": "092720000000", + "Philippsreut (Freyung-Grafenau - Bayern)": "092720000000", + "Thurmansbang (Freyung-Grafenau - Bayern)": "092720000000", + "Zenting (Freyung-Grafenau - Bayern)": "092720000000", + "Fürsteneck (Freyung-Grafenau - Bayern)": "092720000000", + "Perlesreut, M (Freyung-Grafenau - Bayern)": "092720000000", + "Annathaler Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Frauenberger u. Duschlberger Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Graineter Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Leopoldsreuter Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Mauther Forst (Freyung-Grafenau - Bayern)": "092720000000", + "Philippsreuter Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Pleckensteiner Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Sankt Oswald (Freyung-Grafenau - Bayern)": "092720000000", + "Schlichtenberger Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Schönbrunner Wald (Freyung-Grafenau - Bayern)": "092720000000", + "Waldhäuserwald (Freyung-Grafenau - Bayern)": "092720000000", + "Abensberg, St (Kelheim - Bayern)": "092730000000", + "Bad Abbach, M (Kelheim - Bayern)": "092730000000", + "Kelheim, St (Kelheim - Bayern)": "092730000000", + "Mainburg, St (Kelheim - Bayern)": "092730000000", + "Neustadt a.d.Donau, St (Kelheim - Bayern)": "092730000000", + "Painten, M (Kelheim - Bayern)": "092730000000", + "Riedenburg, St (Kelheim - Bayern)": "092730000000", + "Rohr i.NB, M (Kelheim - Bayern)": "092730000000", + "Essing, M (Kelheim - Bayern)": "092730000000", + "Ihrlerstein (Kelheim - Bayern)": "092730000000", + "Saal a.d.Donau (Kelheim - Bayern)": "092730000000", + "Teugn (Kelheim - Bayern)": "092730000000", + "Hausen (Kelheim - Bayern)": "092730000000", + "Herrngiersdorf (Kelheim - Bayern)": "092730000000", + "Langquaid, M (Kelheim - Bayern)": "092730000000", + "Biburg (Kelheim - Bayern)": "092730000000", + "Kirchdorf (Kelheim - Bayern)": "092730000000", + "Siegenburg, M (Kelheim - Bayern)": "092730000000", + "Train (Kelheim - Bayern)": "092730000000", + "Wildenberg (Kelheim - Bayern)": "092730000000", + "Aiglsbach (Kelheim - Bayern)": "092730000000", + "Attenhofen (Kelheim - Bayern)": "092730000000", + "Elsendorf (Kelheim - Bayern)": "092730000000", + "Volkenschwand (Kelheim - Bayern)": "092730000000", + "Dürnbucher Forst (Kelheim - Bayern)": "092730000000", + "Frauenforst (Kelheim - Bayern)": "092730000000", + "Hacklberg (Kelheim - Bayern)": "092730000000", + "Hienheimer Forst (Kelheim - Bayern)": "092730000000", + "Adlkofen (Landshut - Bayern)": "092740000000", + "Altdorf, M (Landshut - Bayern)": "092740000000", + "Bodenkirchen (Landshut - Bayern)": "092740000000", + "Buch a.Erlbach (Landshut - Bayern)": "092740000000", + "Eching (Landshut - Bayern)": "092740000000", + "Ergolding, M (Landshut - Bayern)": "092740000000", + "Essenbach, M (Landshut - Bayern)": "092740000000", + "Geisenhausen, M (Landshut - Bayern)": "092740000000", + "Hohenthann (Landshut - Bayern)": "092740000000", + "Kumhausen (Landshut - Bayern)": "092740000000", + "Neufahrn i.NB (Landshut - Bayern)": "092740000000", + "Niederaichbach (Landshut - Bayern)": "092740000000", + "Pfeffenhausen, M (Landshut - Bayern)": "092740000000", + "Rottenburg a.d.Laaber, St (Landshut - Bayern)": "092740000000", + "Tiefenbach (Landshut - Bayern)": "092740000000", + "Vilsbiburg, St (Landshut - Bayern)": "092740000000", + "Vilsheim (Landshut - Bayern)": "092740000000", + "Bruckberg (Landshut - Bayern)": "092740000000", + "Bayerbach b.Ergoldsbach (Landshut - Bayern)": "092740000000", + "Ergoldsbach, M (Landshut - Bayern)": "092740000000", + "Furth (Landshut - Bayern)": "092740000000", + "Obersüßbach (Landshut - Bayern)": "092740000000", + "Weihmichl (Landshut - Bayern)": "092740000000", + "Postau (Landshut - Bayern)": "092740000000", + "Weng (Landshut - Bayern)": "092740000000", + "Wörth a.d.Isar (Landshut - Bayern)": "092740000000", + "Aham (Landshut - Bayern)": "092740000000", + "Gerzen (Landshut - Bayern)": "092740000000", + "Kröning (Landshut - Bayern)": "092740000000", + "Schalkham (Landshut - Bayern)": "092740000000", + "Altfraunhofen (Landshut - Bayern)": "092740000000", + "Baierbach (Landshut - Bayern)": "092740000000", + "Neufraunhofen (Landshut - Bayern)": "092740000000", + "Velden, M (Landshut - Bayern)": "092740000000", + "Wurmsham (Landshut - Bayern)": "092740000000", + "Aicha vorm Wald (Passau - Bayern)": "092750000000", + "Aldersbach (Passau - Bayern)": "092750000000", + "Bad Füssing (Passau - Bayern)": "092750000000", + "Breitenberg (Passau - Bayern)": "092750000000", + "Büchlberg (Passau - Bayern)": "092750000000", + "Eging a.See, M (Passau - Bayern)": "092750000000", + "Fürstenstein (Passau - Bayern)": "092750000000", + "Fürstenzell, M (Passau - Bayern)": "092750000000", + "Bad Griesbach i.Rottal, St (Passau - Bayern)": "092750000000", + "Haarbach (Passau - Bayern)": "092750000000", + "Hauzenberg, St (Passau - Bayern)": "092750000000", + "Hofkirchen, M (Passau - Bayern)": "092750000000", + "Hutthurm, M (Passau - Bayern)": "092750000000", + "Kirchham (Passau - Bayern)": "092750000000", + "Kößlarn, M (Passau - Bayern)": "092750000000", + "Neuburg a.Inn (Passau - Bayern)": "092750000000", + "Neuhaus a.Inn (Passau - Bayern)": "092750000000", + "Neukirchen vorm Wald (Passau - Bayern)": "092750000000", + "Obernzell, M (Passau - Bayern)": "092750000000", + "Ortenburg, M (Passau - Bayern)": "092750000000", + "Pocking, St (Passau - Bayern)": "092750000000", + "Ruderting (Passau - Bayern)": "092750000000", + "Ruhstorf a.d.Rott, M (Passau - Bayern)": "092750000000", + "Salzweg (Passau - Bayern)": "092750000000", + "Sonnen (Passau - Bayern)": "092750000000", + "Tettenweis (Passau - Bayern)": "092750000000", + "Thyrnau (Passau - Bayern)": "092750000000", + "Tiefenbach (Passau - Bayern)": "092750000000", + "Untergriesbach, M (Passau - Bayern)": "092750000000", + "Vilshofen an der Donau, St (Passau - Bayern)": "092750000000", + "Wegscheid, M (Passau - Bayern)": "092750000000", + "Windorf, M (Passau - Bayern)": "092750000000", + "Tittling, M (Passau - Bayern)": "092750000000", + "Witzmannsberg (Passau - Bayern)": "092750000000", + "Aidenbach, M (Passau - Bayern)": "092750000000", + "Beutelsbach (Passau - Bayern)": "092750000000", + "Malching (Passau - Bayern)": "092750000000", + "Rotthalmünster, M (Passau - Bayern)": "092750000000", + "Arnbruck (Regen - Bayern)": "092760000000", + "Bayerisch Eisenstein (Regen - Bayern)": "092760000000", + "Bischofsmais (Regen - Bayern)": "092760000000", + "Bodenmais, M (Regen - Bayern)": "092760000000", + "Böbrach (Regen - Bayern)": "092760000000", + "Drachselsried (Regen - Bayern)": "092760000000", + "Frauenau (Regen - Bayern)": "092760000000", + "Geiersthal (Regen - Bayern)": "092760000000", + "Kirchberg i.Wald (Regen - Bayern)": "092760000000", + "Kirchdorf i.Wald (Regen - Bayern)": "092760000000", + "Kollnburg (Regen - Bayern)": "092760000000", + "Langdorf (Regen - Bayern)": "092760000000", + "Lindberg (Regen - Bayern)": "092760000000", + "Patersdorf (Regen - Bayern)": "092760000000", + "Prackenbach (Regen - Bayern)": "092760000000", + "Regen, St (Regen - Bayern)": "092760000000", + "Rinchnach (Regen - Bayern)": "092760000000", + "Teisnach, M (Regen - Bayern)": "092760000000", + "Viechtach, St (Regen - Bayern)": "092760000000", + "Zwiesel, St (Regen - Bayern)": "092760000000", + "Achslach (Regen - Bayern)": "092760000000", + "Gotteszell (Regen - Bayern)": "092760000000", + "Ruhmannsfelden, M (Regen - Bayern)": "092760000000", + "Zachenberg (Regen - Bayern)": "092760000000", + "Arnstorf, M (Rottal-Inn - Bayern)": "092770000000", + "Dietersburg (Rottal-Inn - Bayern)": "092770000000", + "Eggenfelden, St (Rottal-Inn - Bayern)": "092770000000", + "Egglham (Rottal-Inn - Bayern)": "092770000000", + "Gangkofen, M (Rottal-Inn - Bayern)": "092770000000", + "Hebertsfelden (Rottal-Inn - Bayern)": "092770000000", + "Johanniskirchen (Rottal-Inn - Bayern)": "092770000000", + "Julbach (Rottal-Inn - Bayern)": "092770000000", + "Kirchdorf a.Inn (Rottal-Inn - Bayern)": "092770000000", + "Mitterskirchen (Rottal-Inn - Bayern)": "092770000000", + "Pfarrkirchen, St (Rottal-Inn - Bayern)": "092770000000", + "Postmünster (Rottal-Inn - Bayern)": "092770000000", + "Roßbach (Rottal-Inn - Bayern)": "092770000000", + "Schönau (Rottal-Inn - Bayern)": "092770000000", + "Simbach a.Inn, St (Rottal-Inn - Bayern)": "092770000000", + "Triftern, M (Rottal-Inn - Bayern)": "092770000000", + "Unterdietfurt (Rottal-Inn - Bayern)": "092770000000", + "Wittibreut (Rottal-Inn - Bayern)": "092770000000", + "Wurmannsquick, M (Rottal-Inn - Bayern)": "092770000000", + "Zeilarn (Rottal-Inn - Bayern)": "092770000000", + "Falkenberg (Rottal-Inn - Bayern)": "092770000000", + "Malgersdorf (Rottal-Inn - Bayern)": "092770000000", + "Rimbach (Rottal-Inn - Bayern)": "092770000000", + "Geratskirchen (Rottal-Inn - Bayern)": "092770000000", + "Massing, M (Rottal-Inn - Bayern)": "092770000000", + "Bayerbach (Rottal-Inn - Bayern)": "092770000000", + "Bad Birnbach, M (Rottal-Inn - Bayern)": "092770000000", + "Reut (Rottal-Inn - Bayern)": "092770000000", + "Tann, M (Rottal-Inn - Bayern)": "092770000000", + "Ering (Rottal-Inn - Bayern)": "092770000000", + "Stubenberg (Rottal-Inn - Bayern)": "092770000000", + "Bogen, St (Straubing-Bogen - Bayern)": "092780000000", + "Feldkirchen (Straubing-Bogen - Bayern)": "092780000000", + "Geiselhöring, St (Straubing-Bogen - Bayern)": "092780000000", + "Haibach (Straubing-Bogen - Bayern)": "092780000000", + "Kirchroth (Straubing-Bogen - Bayern)": "092780000000", + "Konzell (Straubing-Bogen - Bayern)": "092780000000", + "Laberweinting (Straubing-Bogen - Bayern)": "092780000000", + "Leiblfing (Straubing-Bogen - Bayern)": "092780000000", + "Mallersdorf-Pfaffenberg, M (Straubing-Bogen - Bayern)": "092780000000", + "Oberschneiding (Straubing-Bogen - Bayern)": "092780000000", + "Parkstetten (Straubing-Bogen - Bayern)": "092780000000", + "Rattenberg (Straubing-Bogen - Bayern)": "092780000000", + "Sankt Englmar (Straubing-Bogen - Bayern)": "092780000000", + "Steinach (Straubing-Bogen - Bayern)": "092780000000", + "Wiesenfelden (Straubing-Bogen - Bayern)": "092780000000", + "Loitzendorf (Straubing-Bogen - Bayern)": "092780000000", + "Rattiszell (Straubing-Bogen - Bayern)": "092780000000", + "Stallwang (Straubing-Bogen - Bayern)": "092780000000", + "Ascha (Straubing-Bogen - Bayern)": "092780000000", + "Falkenfels (Straubing-Bogen - Bayern)": "092780000000", + "Haselbach (Straubing-Bogen - Bayern)": "092780000000", + "Mitterfels, M (Straubing-Bogen - Bayern)": "092780000000", + "Hunderdorf (Straubing-Bogen - Bayern)": "092780000000", + "Neukirchen (Straubing-Bogen - Bayern)": "092780000000", + "Windberg (Straubing-Bogen - Bayern)": "092780000000", + "Aholfing (Straubing-Bogen - Bayern)": "092780000000", + "Atting (Straubing-Bogen - Bayern)": "092780000000", + "Perkam (Straubing-Bogen - Bayern)": "092780000000", + "Rain (Straubing-Bogen - Bayern)": "092780000000", + "Mariaposching (Straubing-Bogen - Bayern)": "092780000000", + "Niederwinkling (Straubing-Bogen - Bayern)": "092780000000", + "Perasdorf (Straubing-Bogen - Bayern)": "092780000000", + "Schwarzach, M (Straubing-Bogen - Bayern)": "092780000000", + "Aiterhofen (Straubing-Bogen - Bayern)": "092780000000", + "Salching (Straubing-Bogen - Bayern)": "092780000000", + "Irlbach (Straubing-Bogen - Bayern)": "092780000000", + "Straßkirchen (Straubing-Bogen - Bayern)": "092780000000", + "Dingolfing, St (Dingolfing-Landau - Bayern)": "092790000000", + "Eichendorf, M (Dingolfing-Landau - Bayern)": "092790000000", + "Frontenhausen, M (Dingolfing-Landau - Bayern)": "092790000000", + "Landau a.d.Isar, St (Dingolfing-Landau - Bayern)": "092790000000", + "Loiching (Dingolfing-Landau - Bayern)": "092790000000", + "Marklkofen (Dingolfing-Landau - Bayern)": "092790000000", + "Mengkofen (Dingolfing-Landau - Bayern)": "092790000000", + "Moosthenning (Dingolfing-Landau - Bayern)": "092790000000", + "Niederviehbach (Dingolfing-Landau - Bayern)": "092790000000", + "Pilsting, M (Dingolfing-Landau - Bayern)": "092790000000", + "Reisbach, M (Dingolfing-Landau - Bayern)": "092790000000", + "Simbach, M (Dingolfing-Landau - Bayern)": "092790000000", + "Wallersdorf, M (Dingolfing-Landau - Bayern)": "092790000000", + "Gottfrieding (Dingolfing-Landau - Bayern)": "092790000000", + "Mamming (Dingolfing-Landau - Bayern)": "092790000000", + "Amberg": "093610000000", + "Regensburg": "093620000000", + "Weiden i.d.OPf.": "093630000000", + "Ammerthal (Amberg-Sulzbach - Bayern)": "093710000000", + "Auerbach i.d.OPf., St (Amberg-Sulzbach - Bayern)": "093710000000", + "Ebermannsdorf (Amberg-Sulzbach - Bayern)": "093710000000", + "Edelsfeld (Amberg-Sulzbach - Bayern)": "093710000000", + "Ensdorf (Amberg-Sulzbach - Bayern)": "093710000000", + "Freihung, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Freudenberg (Amberg-Sulzbach - Bayern)": "093710000000", + "Hirschau, St (Amberg-Sulzbach - Bayern)": "093710000000", + "Hohenburg, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Kastl, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Kümmersbruck (Amberg-Sulzbach - Bayern)": "093710000000", + "Poppenricht (Amberg-Sulzbach - Bayern)": "093710000000", + "Rieden, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Schmidmühlen, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Schnaittenbach, St (Amberg-Sulzbach - Bayern)": "093710000000", + "Sulzbach-Rosenberg, St (Amberg-Sulzbach - Bayern)": "093710000000", + "Ursensollen (Amberg-Sulzbach - Bayern)": "093710000000", + "Vilseck, St (Amberg-Sulzbach - Bayern)": "093710000000", + "Gebenbach (Amberg-Sulzbach - Bayern)": "093710000000", + "Hahnbach, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Hirschbach (Amberg-Sulzbach - Bayern)": "093710000000", + "Königstein, M (Amberg-Sulzbach - Bayern)": "093710000000", + "Etzelwang (Amberg-Sulzbach - Bayern)": "093710000000", + "Neukirchen b.Sulzbach-Rosenberg (Amberg-Sulzbach - Bayern)": "093710000000", + "Weigendorf (Amberg-Sulzbach - Bayern)": "093710000000", + "Birgland (Amberg-Sulzbach - Bayern)": "093710000000", + "Illschwang (Amberg-Sulzbach - Bayern)": "093710000000", + "Eichen (Amberg-Sulzbach - Bayern)": "093710000000", + "Arnschwang (Cham - Bayern)": "093720000000", + "Arrach (Cham - Bayern)": "093720000000", + "Blaibach (Cham - Bayern)": "093720000000", + "Cham, St (Cham - Bayern)": "093720000000", + "Chamerau (Cham - Bayern)": "093720000000", + "Eschlkam, M (Cham - Bayern)": "093720000000", + "Furth im Wald, St (Cham - Bayern)": "093720000000", + "Grafenwiesen (Cham - Bayern)": "093720000000", + "Hohenwarth (Cham - Bayern)": "093720000000", + "Bad Kötzting, St (Cham - Bayern)": "093720000000", + "Lam, M (Cham - Bayern)": "093720000000", + "Miltach (Cham - Bayern)": "093720000000", + "Neukirchen b.Hl.Blut, M (Cham - Bayern)": "093720000000", + "Pemfling (Cham - Bayern)": "093720000000", + "Rimbach (Cham - Bayern)": "093720000000", + "Roding, St (Cham - Bayern)": "093720000000", + "Rötz, St (Cham - Bayern)": "093720000000", + "Runding (Cham - Bayern)": "093720000000", + "Schönthal (Cham - Bayern)": "093720000000", + "Schorndorf (Cham - Bayern)": "093720000000", + "Traitsching (Cham - Bayern)": "093720000000", + "Waffenbrunn (Cham - Bayern)": "093720000000", + "Waldmünchen, St (Cham - Bayern)": "093720000000", + "Willmering (Cham - Bayern)": "093720000000", + "Zandt (Cham - Bayern)": "093720000000", + "Lohberg (Cham - Bayern)": "093720000000", + "Tiefenbach (Cham - Bayern)": "093720000000", + "Treffelstein (Cham - Bayern)": "093720000000", + "Pösing (Cham - Bayern)": "093720000000", + "Stamsried, M (Cham - Bayern)": "093720000000", + "Gleißenberg (Cham - Bayern)": "093720000000", + "Weiding (Cham - Bayern)": "093720000000", + "Reichenbach (Cham - Bayern)": "093720000000", + "Walderbach (Cham - Bayern)": "093720000000", + "Zell (Cham - Bayern)": "093720000000", + "Wald (Cham - Bayern)": "093720000000", + "Falkenstein, M (Cham - Bayern)": "093720000000", + "Michelsneukirchen (Cham - Bayern)": "093720000000", + "Rettenbach (Cham - Bayern)": "093720000000", + "Berching, St (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Berg b.Neumarkt i.d.OPf. (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Breitenbrunn, M (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Deining (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Dietfurt a.d.Altmühl, St (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Freystadt, St (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Hohenfels, M (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Lauterhofen, M (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Lupburg, M (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Mühlhausen (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Neumarkt i.d.OPf., GKSt (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Parsberg, St (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Postbauer-Heng, M (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Pyrbaum, M (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Seubersdorf i.d.OPf. (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Velburg, St (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Berngau (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Pilsach (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Sengenthal (Neumarkt in der Oberpfalz - Bayern)": "093730000000", + "Altenstadt a.d.Waldnaab (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Eslarn, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Floß, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Flossenbürg (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Grafenwöhr, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Luhe-Wildenau, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Mantel, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Moosbach, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Neustadt a.d.Waldnaab, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Vohenstrauß, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Waidhaus, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Waldthurn, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Windischeschenbach, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Kirchendemenreuth (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Parkstein, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Püchersreuth (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Störnstein (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Theisseil (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Trabitz (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Pressath, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Schwarzenbach (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Etzenricht (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Kohlberg, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Weiherhammer (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Kirchenthumbach, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Schlammersdorf (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Vorbach (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Eschenbach i.d.OPf., St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Neustadt am Kulm, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Speinshart (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Irchenrieth (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Pirk (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Schirmitz (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Bechtsrieth (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Leuchtenberg, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Tännesberg, M (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Georgenberg (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Pleystein, St (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Heinersreuther Forst (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Manteler Forst (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Speinsharter Forst (Neustadt an der Waldnaab - Bayern)": "093740000000", + "Barbing (Regensburg - Bayern)": "093750000000", + "Beratzhausen, M (Regensburg - Bayern)": "093750000000", + "Bernhardswald (Regensburg - Bayern)": "093750000000", + "Hagelstadt (Regensburg - Bayern)": "093750000000", + "Hemau, St (Regensburg - Bayern)": "093750000000", + "Köfering (Regensburg - Bayern)": "093750000000", + "Lappersdorf, M (Regensburg - Bayern)": "093750000000", + "Mintraching (Regensburg - Bayern)": "093750000000", + "Neutraubling, St (Regensburg - Bayern)": "093750000000", + "Nittendorf, M (Regensburg - Bayern)": "093750000000", + "Obertraubling (Regensburg - Bayern)": "093750000000", + "Pentling (Regensburg - Bayern)": "093750000000", + "Pettendorf (Regensburg - Bayern)": "093750000000", + "Pfatter (Regensburg - Bayern)": "093750000000", + "Regenstauf, M (Regensburg - Bayern)": "093750000000", + "Schierling, M (Regensburg - Bayern)": "093750000000", + "Sinzing (Regensburg - Bayern)": "093750000000", + "Tegernheim (Regensburg - Bayern)": "093750000000", + "Thalmassing (Regensburg - Bayern)": "093750000000", + "Wenzenbach (Regensburg - Bayern)": "093750000000", + "Wiesent (Regensburg - Bayern)": "093750000000", + "Zeitlarn (Regensburg - Bayern)": "093750000000", + "Duggendorf (Regensburg - Bayern)": "093750000000", + "Holzheim a.Forst (Regensburg - Bayern)": "093750000000", + "Kallmünz, M (Regensburg - Bayern)": "093750000000", + "Brunn (Regensburg - Bayern)": "093750000000", + "Deuerling (Regensburg - Bayern)": "093750000000", + "Laaber, M (Regensburg - Bayern)": "093750000000", + "Pielenhofen (Regensburg - Bayern)": "093750000000", + "Wolfsegg (Regensburg - Bayern)": "093750000000", + "Altenthann (Regensburg - Bayern)": "093750000000", + "Bach a.d.Donau (Regensburg - Bayern)": "093750000000", + "Donaustauf, M (Regensburg - Bayern)": "093750000000", + "Brennberg (Regensburg - Bayern)": "093750000000", + "Wörth a.d.Donau, St (Regensburg - Bayern)": "093750000000", + "Alteglofsheim (Regensburg - Bayern)": "093750000000", + "Pfakofen (Regensburg - Bayern)": "093750000000", + "Aufhausen (Regensburg - Bayern)": "093750000000", + "Mötzing (Regensburg - Bayern)": "093750000000", + "Riekofen (Regensburg - Bayern)": "093750000000", + "Sünching (Regensburg - Bayern)": "093750000000", + "Forstmühler Forst (Regensburg - Bayern)": "093750000000", + "Kreuther Forst (Regensburg - Bayern)": "093750000000", + "Bodenwöhr (Schwandorf - Bayern)": "093760000000", + "Bruck i.d.OPf., M (Schwandorf - Bayern)": "093760000000", + "Burglengenfeld, St (Schwandorf - Bayern)": "093760000000", + "Fensterbach (Schwandorf - Bayern)": "093760000000", + "Maxhütte-Haidhof, St (Schwandorf - Bayern)": "093760000000", + "Neunburg vorm Wald, St (Schwandorf - Bayern)": "093760000000", + "Nittenau, St (Schwandorf - Bayern)": "093760000000", + "Wernberg-Köblitz, M (Schwandorf - Bayern)": "093760000000", + "Oberviechtach, St (Schwandorf - Bayern)": "093760000000", + "Schmidgaden (Schwandorf - Bayern)": "093760000000", + "Schwandorf, GKSt (Schwandorf - Bayern)": "093760000000", + "Teublitz, St (Schwandorf - Bayern)": "093760000000", + "Gleiritsch (Schwandorf - Bayern)": "093760000000", + "Niedermurach (Schwandorf - Bayern)": "093760000000", + "Teunz (Schwandorf - Bayern)": "093760000000", + "Winklarn, M (Schwandorf - Bayern)": "093760000000", + "Altendorf (Schwandorf - Bayern)": "093760000000", + "Guteneck (Schwandorf - Bayern)": "093760000000", + "Nabburg, St (Schwandorf - Bayern)": "093760000000", + "Schwarzach b.Nabburg (Schwandorf - Bayern)": "093760000000", + "Schwarzenfeld, M (Schwandorf - Bayern)": "093760000000", + "Stulln (Schwandorf - Bayern)": "093760000000", + "Pfreimd, St (Schwandorf - Bayern)": "093760000000", + "Trausnitz (Schwandorf - Bayern)": "093760000000", + "Schönsee, St (Schwandorf - Bayern)": "093760000000", + "Stadlern (Schwandorf - Bayern)": "093760000000", + "Weiding (Schwandorf - Bayern)": "093760000000", + "Dieterskirchen (Schwandorf - Bayern)": "093760000000", + "Neukirchen-Balbini, M (Schwandorf - Bayern)": "093760000000", + "Schwarzhofen, M (Schwandorf - Bayern)": "093760000000", + "Thanstein (Schwandorf - Bayern)": "093760000000", + "Steinberg am See (Schwandorf - Bayern)": "093760000000", + "Wackersdorf (Schwandorf - Bayern)": "093760000000", + "Wolferlohe (Schwandorf - Bayern)": "093760000000", + "Bärnau, St (Tirschenreuth - Bayern)": "093770000000", + "Erbendorf, St (Tirschenreuth - Bayern)": "093770000000", + "Friedenfels (Tirschenreuth - Bayern)": "093770000000", + "Fuchsmühl, M (Tirschenreuth - Bayern)": "093770000000", + "Immenreuth (Tirschenreuth - Bayern)": "093770000000", + "Konnersreuth, M (Tirschenreuth - Bayern)": "093770000000", + "Kulmain (Tirschenreuth - Bayern)": "093770000000", + "Mähring, M (Tirschenreuth - Bayern)": "093770000000", + "Bad Neualbenreuth, M (Tirschenreuth - Bayern)": "093770000000", + "Plößberg, M (Tirschenreuth - Bayern)": "093770000000", + "Tirschenreuth, St (Tirschenreuth - Bayern)": "093770000000", + "Waldershof, St (Tirschenreuth - Bayern)": "093770000000", + "Waldsassen, St (Tirschenreuth - Bayern)": "093770000000", + "Leonberg (Tirschenreuth - Bayern)": "093770000000", + "Mitterteich, St (Tirschenreuth - Bayern)": "093770000000", + "Pechbrunn (Tirschenreuth - Bayern)": "093770000000", + "Kastl (Tirschenreuth - Bayern)": "093770000000", + "Kemnath, St (Tirschenreuth - Bayern)": "093770000000", + "Brand (Tirschenreuth - Bayern)": "093770000000", + "Ebnath (Tirschenreuth - Bayern)": "093770000000", + "Neusorg (Tirschenreuth - Bayern)": "093770000000", + "Pullenreuth (Tirschenreuth - Bayern)": "093770000000", + "Krummennaab (Tirschenreuth - Bayern)": "093770000000", + "Reuth b.Erbendorf (Tirschenreuth - Bayern)": "093770000000", + "Falkenberg, M (Tirschenreuth - Bayern)": "093770000000", + "Wiesau, M (Tirschenreuth - Bayern)": "093770000000", + "Bamberg": "094610000000", + "Bayreuth": "094620000000", + "Coburg": "094630000000", + "Hof": "094640000000", + "Altendorf (Bamberg - Bayern)": "094710000000", + "Bischberg (Bamberg - Bayern)": "094710000000", + "Breitengüßbach (Bamberg - Bayern)": "094710000000", + "Buttenheim, M (Bamberg - Bayern)": "094710000000", + "Frensdorf (Bamberg - Bayern)": "094710000000", + "Gundelsheim (Bamberg - Bayern)": "094710000000", + "Hallstadt, St (Bamberg - Bayern)": "094710000000", + "Heiligenstadt i.OFr., M (Bamberg - Bayern)": "094710000000", + "Hirschaid, M (Bamberg - Bayern)": "094710000000", + "Kemmern (Bamberg - Bayern)": "094710000000", + "Litzendorf (Bamberg - Bayern)": "094710000000", + "Memmelsdorf (Bamberg - Bayern)": "094710000000", + "Oberhaid (Bamberg - Bayern)": "094710000000", + "Pettstadt (Bamberg - Bayern)": "094710000000", + "Pommersfelden (Bamberg - Bayern)": "094710000000", + "Rattelsdorf, M (Bamberg - Bayern)": "094710000000", + "Scheßlitz, St (Bamberg - Bayern)": "094710000000", + "Stegaurach (Bamberg - Bayern)": "094710000000", + "Strullendorf (Bamberg - Bayern)": "094710000000", + "Viereth-Trunstadt (Bamberg - Bayern)": "094710000000", + "Walsdorf (Bamberg - Bayern)": "094710000000", + "Zapfendorf, M (Bamberg - Bayern)": "094710000000", + "Schlüsselfeld, St (Bamberg - Bayern)": "094710000000", + "Baunach, St (Bamberg - Bayern)": "094710000000", + "Gerach (Bamberg - Bayern)": "094710000000", + "Lauter (Bamberg - Bayern)": "094710000000", + "Reckendorf (Bamberg - Bayern)": "094710000000", + "Königsfeld (Bamberg - Bayern)": "094710000000", + "Stadelhofen (Bamberg - Bayern)": "094710000000", + "Wattendorf (Bamberg - Bayern)": "094710000000", + "Burgwindheim, M (Bamberg - Bayern)": "094710000000", + "Ebrach, M (Bamberg - Bayern)": "094710000000", + "Burgebrach, M (Bamberg - Bayern)": "094710000000", + "Schönbrunn i.Steigerwald (Bamberg - Bayern)": "094710000000", + "Lisberg (Bamberg - Bayern)": "094710000000", + "Priesendorf (Bamberg - Bayern)": "094710000000", + "Ebracher Forst (Bamberg - Bayern)": "094710000000", + "Eichwald (Bamberg - Bayern)": "094710000000", + "Geisberger Forst (Bamberg - Bayern)": "094710000000", + "Hauptsmoor (Bamberg - Bayern)": "094710000000", + "Koppenwinder Forst (Bamberg - Bayern)": "094710000000", + "Lindach (Bamberg - Bayern)": "094710000000", + "Semberg (Bamberg - Bayern)": "094710000000", + "Steinachsrangen (Bamberg - Bayern)": "094710000000", + "Winkelhofer Forst (Bamberg - Bayern)": "094710000000", + "Zückshuter Forst (Bamberg - Bayern)": "094710000000", + "Ahorntal (Bayreuth - Bayern)": "094720000000", + "Bad Berneck i.Fichtelgebirge, St (Bayreuth - Bayern)": "094720000000", + "Bindlach (Bayreuth - Bayern)": "094720000000", + "Bischofsgrün (Bayreuth - Bayern)": "094720000000", + "Eckersdorf (Bayreuth - Bayern)": "094720000000", + "Fichtelberg (Bayreuth - Bayern)": "094720000000", + "Gefrees, St (Bayreuth - Bayern)": "094720000000", + "Goldkronach, St (Bayreuth - Bayern)": "094720000000", + "Heinersreuth (Bayreuth - Bayern)": "094720000000", + "Mehlmeisel (Bayreuth - Bayern)": "094720000000", + "Pegnitz, St (Bayreuth - Bayern)": "094720000000", + "Pottenstein, St (Bayreuth - Bayern)": "094720000000", + "Speichersdorf (Bayreuth - Bayern)": "094720000000", + "Waischenfeld, St (Bayreuth - Bayern)": "094720000000", + "Warmensteinach (Bayreuth - Bayern)": "094720000000", + "Aufseß (Bayreuth - Bayern)": "094720000000", + "Hollfeld, St (Bayreuth - Bayern)": "094720000000", + "Plankenfels (Bayreuth - Bayern)": "094720000000", + "Glashütten (Bayreuth - Bayern)": "094720000000", + "Mistelgau (Bayreuth - Bayern)": "094720000000", + "Gesees (Bayreuth - Bayern)": "094720000000", + "Hummeltal (Bayreuth - Bayern)": "094720000000", + "Mistelbach (Bayreuth - Bayern)": "094720000000", + "Emtmannsberg (Bayreuth - Bayern)": "094720000000", + "Kirchenpingarten (Bayreuth - Bayern)": "094720000000", + "Seybothenreuth (Bayreuth - Bayern)": "094720000000", + "Weidenberg, M (Bayreuth - Bayern)": "094720000000", + "Creußen, St (Bayreuth - Bayern)": "094720000000", + "Haag (Bayreuth - Bayern)": "094720000000", + "Prebitz (Bayreuth - Bayern)": "094720000000", + "Schnabelwaid, M (Bayreuth - Bayern)": "094720000000", + "Betzenstein, St (Bayreuth - Bayern)": "094720000000", + "Plech, M (Bayreuth - Bayern)": "094720000000", + "Bischofsgrüner Forst (Bayreuth - Bayern)": "094720000000", + "Forst Neustädtlein a.Forst (Bayreuth - Bayern)": "094720000000", + "Glashüttener Forst (Bayreuth - Bayern)": "094720000000", + "Heinersreuther Forst (Bayreuth - Bayern)": "094720000000", + "Neubauer Forst-Nord (Bayreuth - Bayern)": "094720000000", + "Prüll (Bayreuth - Bayern)": "094720000000", + "Veldensteinerforst (Bayreuth - Bayern)": "094720000000", + "Waidacher Forst (Bayreuth - Bayern)": "094720000000", + "Warmensteinacher Forst-Nord (Bayreuth - Bayern)": "094720000000", + "Ahorn (Coburg - Bayern)": "094730000000", + "Dörfles-Esbach (Coburg - Bayern)": "094730000000", + "Ebersdorf b.Coburg (Coburg - Bayern)": "094730000000", + "Großheirath (Coburg - Bayern)": "094730000000", + "Itzgrund (Coburg - Bayern)": "094730000000", + "Lautertal (Coburg - Bayern)": "094730000000", + "Meeder (Coburg - Bayern)": "094730000000", + "Neustadt b.Coburg, GKSt (Coburg - Bayern)": "094730000000", + "Bad Rodach, St (Coburg - Bayern)": "094730000000", + "Rödental, St (Coburg - Bayern)": "094730000000", + "Seßlach, St (Coburg - Bayern)": "094730000000", + "Sonnefeld (Coburg - Bayern)": "094730000000", + "Untersiemau (Coburg - Bayern)": "094730000000", + "Weidhausen b.Coburg (Coburg - Bayern)": "094730000000", + "Weitramsdorf (Coburg - Bayern)": "094730000000", + "Grub a.Forst (Coburg - Bayern)": "094730000000", + "Niederfüllbach (Coburg - Bayern)": "094730000000", + "Callenberger Forst-West (Coburg - Bayern)": "094730000000", + "Gellnhausen (Coburg - Bayern)": "094730000000", + "Köllnholz (Coburg - Bayern)": "094730000000", + "Eggolsheim, M (Forchheim - Bayern)": "094740000000", + "Egloffstein, M (Forchheim - Bayern)": "094740000000", + "Forchheim, GKSt (Forchheim - Bayern)": "094740000000", + "Gößweinstein, M (Forchheim - Bayern)": "094740000000", + "Hallerndorf (Forchheim - Bayern)": "094740000000", + "Hausen (Forchheim - Bayern)": "094740000000", + "Heroldsbach (Forchheim - Bayern)": "094740000000", + "Igensdorf, M (Forchheim - Bayern)": "094740000000", + "Langensendelbach (Forchheim - Bayern)": "094740000000", + "Neunkirchen a.Brand, M (Forchheim - Bayern)": "094740000000", + "Obertrubach (Forchheim - Bayern)": "094740000000", + "Pretzfeld, M (Forchheim - Bayern)": "094740000000", + "Wiesenttal, M (Forchheim - Bayern)": "094740000000", + "Ebermannstadt, St (Forchheim - Bayern)": "094740000000", + "Unterleinleiter (Forchheim - Bayern)": "094740000000", + "Kunreuth (Forchheim - Bayern)": "094740000000", + "Pinzberg (Forchheim - Bayern)": "094740000000", + "Wiesenthau (Forchheim - Bayern)": "094740000000", + "Kirchehrenbach (Forchheim - Bayern)": "094740000000", + "Leutenbach (Forchheim - Bayern)": "094740000000", + "Weilersbach (Forchheim - Bayern)": "094740000000", + "Effeltrich (Forchheim - Bayern)": "094740000000", + "Poxdorf (Forchheim - Bayern)": "094740000000", + "Dormitz (Forchheim - Bayern)": "094740000000", + "Hetzles (Forchheim - Bayern)": "094740000000", + "Kleinsendelbach (Forchheim - Bayern)": "094740000000", + "Gräfenberg, St (Forchheim - Bayern)": "094740000000", + "Hiltpoltstein, M (Forchheim - Bayern)": "094740000000", + "Weißenohe (Forchheim - Bayern)": "094740000000", + "Bad Steben, M (Hof - Bayern)": "094750000000", + "Berg (Hof - Bayern)": "094750000000", + "Döhlau (Hof - Bayern)": "094750000000", + "Geroldsgrün (Hof - Bayern)": "094750000000", + "Helmbrechts, St (Hof - Bayern)": "094750000000", + "Köditz (Hof - Bayern)": "094750000000", + "Konradsreuth (Hof - Bayern)": "094750000000", + "Münchberg, St (Hof - Bayern)": "094750000000", + "Naila, St (Hof - Bayern)": "094750000000", + "Oberkotzau, M (Hof - Bayern)": "094750000000", + "Regnitzlosau (Hof - Bayern)": "094750000000", + "Rehau, St (Hof - Bayern)": "094750000000", + "Schwarzenbach a.d.Saale, St (Hof - Bayern)": "094750000000", + "Schwarzenbach a.Wald, St (Hof - Bayern)": "094750000000", + "Selbitz, St (Hof - Bayern)": "094750000000", + "Stammbach, M (Hof - Bayern)": "094750000000", + "Zell im Fichtelgebirge, M (Hof - Bayern)": "094750000000", + "Issigau (Hof - Bayern)": "094750000000", + "Lichtenberg, St (Hof - Bayern)": "094750000000", + "Feilitzsch (Hof - Bayern)": "094750000000", + "Gattendorf (Hof - Bayern)": "094750000000", + "Töpen (Hof - Bayern)": "094750000000", + "Trogen (Hof - Bayern)": "094750000000", + "Leupoldsgrün (Hof - Bayern)": "094750000000", + "Schauenstein, St (Hof - Bayern)": "094750000000", + "Sparneck, M (Hof - Bayern)": "094750000000", + "Weißdorf (Hof - Bayern)": "094750000000", + "Forst Schwarzenbach a.Wald (Hof - Bayern)": "094750000000", + "Gerlaser Forst (Hof - Bayern)": "094750000000", + "Geroldsgrüner Forst (Hof - Bayern)": "094750000000", + "Martinlamitzer Forst-Nord (Hof - Bayern)": "094750000000", + "Kronach, St (Kronach - Bayern)": "094760000000", + "Küps, M (Kronach - Bayern)": "094760000000", + "Ludwigsstadt, St (Kronach - Bayern)": "094760000000", + "Nordhalben, M (Kronach - Bayern)": "094760000000", + "Pressig, M (Kronach - Bayern)": "094760000000", + "Steinbach a.Wald (Kronach - Bayern)": "094760000000", + "Steinwiesen, M (Kronach - Bayern)": "094760000000", + "Stockheim (Kronach - Bayern)": "094760000000", + "Tettau, M (Kronach - Bayern)": "094760000000", + "Marktrodach, M (Kronach - Bayern)": "094760000000", + "Wallenfels, St (Kronach - Bayern)": "094760000000", + "Weißenbrunn (Kronach - Bayern)": "094760000000", + "Wilhelmsthal (Kronach - Bayern)": "094760000000", + "Reichenbach (Kronach - Bayern)": "094760000000", + "Teuschnitz, St (Kronach - Bayern)": "094760000000", + "Tschirn (Kronach - Bayern)": "094760000000", + "Mitwitz, M (Kronach - Bayern)": "094760000000", + "Schneckenlohe (Kronach - Bayern)": "094760000000", + "Birnbaum (Kronach - Bayern)": "094760000000", + "Langenbacher Forst (Kronach - Bayern)": "094760000000", + "Himmelkron (Kulmbach - Bayern)": "094770000000", + "Kulmbach, GKSt (Kulmbach - Bayern)": "094770000000", + "Mainleus, M (Kulmbach - Bayern)": "094770000000", + "Marktschorgast, M (Kulmbach - Bayern)": "094770000000", + "Neudrossenfeld (Kulmbach - Bayern)": "094770000000", + "Neuenmarkt (Kulmbach - Bayern)": "094770000000", + "Presseck, M (Kulmbach - Bayern)": "094770000000", + "Thurnau, M (Kulmbach - Bayern)": "094770000000", + "Wirsberg, M (Kulmbach - Bayern)": "094770000000", + "Rugendorf (Kulmbach - Bayern)": "094770000000", + "Stadtsteinach, St (Kulmbach - Bayern)": "094770000000", + "Grafengehaig, M (Kulmbach - Bayern)": "094770000000", + "Marktleugast, M (Kulmbach - Bayern)": "094770000000", + "Guttenberg (Kulmbach - Bayern)": "094770000000", + "Kupferberg, St (Kulmbach - Bayern)": "094770000000", + "Ludwigschorgast, M (Kulmbach - Bayern)": "094770000000", + "Untersteinach (Kulmbach - Bayern)": "094770000000", + "Kasendorf, M (Kulmbach - Bayern)": "094770000000", + "Wonsees, M (Kulmbach - Bayern)": "094770000000", + "Harsdorf (Kulmbach - Bayern)": "094770000000", + "Ködnitz (Kulmbach - Bayern)": "094770000000", + "Trebgast (Kulmbach - Bayern)": "094770000000", + "Altenkunstadt (Lichtenfels - Bayern)": "094780000000", + "Burgkunstadt, St (Lichtenfels - Bayern)": "094780000000", + "Ebensfeld, M (Lichtenfels - Bayern)": "094780000000", + "Lichtenfels, St (Lichtenfels - Bayern)": "094780000000", + "Michelau i.OFr. (Lichtenfels - Bayern)": "094780000000", + "Bad Staffelstein, St (Lichtenfels - Bayern)": "094780000000", + "Weismain, St (Lichtenfels - Bayern)": "094780000000", + "Marktgraitz, M (Lichtenfels - Bayern)": "094780000000", + "Redwitz a.d.Rodach (Lichtenfels - Bayern)": "094780000000", + "Hochstadt a.Main (Lichtenfels - Bayern)": "094780000000", + "Marktzeuln, M (Lichtenfels - Bayern)": "094780000000", + "Breitengüßbacher Forst (Lichtenfels - Bayern)": "094780000000", + "Neuensorger Forst (Lichtenfels - Bayern)": "094780000000", + "Arzberg, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Kirchenlamitz, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Marktleuthen, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Marktredwitz, GKSt (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Röslau (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Schönwald, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Selb, GKSt (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Weißenstadt, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Wunsiedel, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Höchstädt i.Fichtelgebirge (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Thiersheim, M (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Thierstein, M (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Hohenberg a.d.Eger, St (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Schirnding, M (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Bad Alexandersbad (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Nagel (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Tröstau (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Kaiserhammer Forst-Ost (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Martinlamitzer Forst-Süd (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Meierhöfer Seite (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Neubauer Forst-Süd (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Tröstauer Forst-Ost (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Tröstauer Forst-West (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Vordorfer Forst (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Weißenstadter Forst-Nord (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Weißenstadter Forst-Süd (Wunsiedel im Fichtelgebirge - Bayern)": "094790000000", + "Ansbach": "095610000000", + "Erlangen": "095620000000", + "Fürth": "095630000000", + "Nürnberg": "095640000000", + "Schwabach": "095650000000", + "Arberg, M (Ansbach - Bayern)": "095710000000", + "Aurach (Ansbach - Bayern)": "095710000000", + "Bechhofen, M (Ansbach - Bayern)": "095710000000", + "Burgoberbach (Ansbach - Bayern)": "095710000000", + "Colmberg, M (Ansbach - Bayern)": "095710000000", + "Dietenhofen, M (Ansbach - Bayern)": "095710000000", + "Dinkelsbühl, GKSt (Ansbach - Bayern)": "095710000000", + "Dürrwangen, M (Ansbach - Bayern)": "095710000000", + "Feuchtwangen, St (Ansbach - Bayern)": "095710000000", + "Flachslanden, M (Ansbach - Bayern)": "095710000000", + "Heilsbronn, St (Ansbach - Bayern)": "095710000000", + "Herrieden, St (Ansbach - Bayern)": "095710000000", + "Langfurth (Ansbach - Bayern)": "095710000000", + "Lehrberg, M (Ansbach - Bayern)": "095710000000", + "Leutershausen, St (Ansbach - Bayern)": "095710000000", + "Lichtenau, M (Ansbach - Bayern)": "095710000000", + "Merkendorf, St (Ansbach - Bayern)": "095710000000", + "Neuendettelsau (Ansbach - Bayern)": "095710000000", + "Oberdachstetten (Ansbach - Bayern)": "095710000000", + "Petersaurach (Ansbach - Bayern)": "095710000000", + "Rothenburg ob der Tauber, GKSt (Ansbach - Bayern)": "095710000000", + "Sachsen b.Ansbach (Ansbach - Bayern)": "095710000000", + "Schnelldorf (Ansbach - Bayern)": "095710000000", + "Schopfloch, M (Ansbach - Bayern)": "095710000000", + "Wassertrüdingen, St (Ansbach - Bayern)": "095710000000", + "Windsbach, St (Ansbach - Bayern)": "095710000000", + "Adelshofen (Ansbach - Bayern)": "095710000000", + "Gebsattel (Ansbach - Bayern)": "095710000000", + "Geslau (Ansbach - Bayern)": "095710000000", + "Insingen (Ansbach - Bayern)": "095710000000", + "Neusitz (Ansbach - Bayern)": "095710000000", + "Ohrenbach (Ansbach - Bayern)": "095710000000", + "Steinsfeld (Ansbach - Bayern)": "095710000000", + "Windelsbach (Ansbach - Bayern)": "095710000000", + "Buch a.Wald (Ansbach - Bayern)": "095710000000", + "Diebach (Ansbach - Bayern)": "095710000000", + "Dombühl, M (Ansbach - Bayern)": "095710000000", + "Schillingsfürst, St (Ansbach - Bayern)": "095710000000", + "Wettringen (Ansbach - Bayern)": "095710000000", + "Wörnitz (Ansbach - Bayern)": "095710000000", + "Bruckberg (Ansbach - Bayern)": "095710000000", + "Rügland (Ansbach - Bayern)": "095710000000", + "Weihenzell (Ansbach - Bayern)": "095710000000", + "Ornbau, St (Ansbach - Bayern)": "095710000000", + "Weidenbach, M (Ansbach - Bayern)": "095710000000", + "Burk (Ansbach - Bayern)": "095710000000", + "Dentlein a.Forst, M (Ansbach - Bayern)": "095710000000", + "Wieseth (Ansbach - Bayern)": "095710000000", + "Mönchsroth (Ansbach - Bayern)": "095710000000", + "Weiltingen, M (Ansbach - Bayern)": "095710000000", + "Wilburgstetten (Ansbach - Bayern)": "095710000000", + "Ehingen (Ansbach - Bayern)": "095710000000", + "Gerolfingen (Ansbach - Bayern)": "095710000000", + "Röckingen (Ansbach - Bayern)": "095710000000", + "Unterschwaningen (Ansbach - Bayern)": "095710000000", + "Wittelshofen (Ansbach - Bayern)": "095710000000", + "Mitteleschenbach (Ansbach - Bayern)": "095710000000", + "Wolframs-Eschenbach, St (Ansbach - Bayern)": "095710000000", + "Unterer Wald (Ansbach - Bayern)": "095710000000", + "Adelsdorf (Erlangen-Höchstadt - Bayern)": "095720000000", + "Baiersdorf, St (Erlangen-Höchstadt - Bayern)": "095720000000", + "Bubenreuth (Erlangen-Höchstadt - Bayern)": "095720000000", + "Eckental, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Hemhofen (Erlangen-Höchstadt - Bayern)": "095720000000", + "Heroldsberg, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Herzogenaurach, St (Erlangen-Höchstadt - Bayern)": "095720000000", + "Höchstadt a.d.Aisch, St (Erlangen-Höchstadt - Bayern)": "095720000000", + "Kalchreuth (Erlangen-Höchstadt - Bayern)": "095720000000", + "Möhrendorf (Erlangen-Höchstadt - Bayern)": "095720000000", + "Röttenbach (Erlangen-Höchstadt - Bayern)": "095720000000", + "Wachenroth, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Weisendorf, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Gremsdorf (Erlangen-Höchstadt - Bayern)": "095720000000", + "Lonnerstadt, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Mühlhausen, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Vestenbergsgreuth, M (Erlangen-Höchstadt - Bayern)": "095720000000", + "Aurachtal (Erlangen-Höchstadt - Bayern)": "095720000000", + "Oberreichenbach (Erlangen-Höchstadt - Bayern)": "095720000000", + "Buckenhof (Erlangen-Höchstadt - Bayern)": "095720000000", + "Marloffstein (Erlangen-Höchstadt - Bayern)": "095720000000", + "Spardorf (Erlangen-Höchstadt - Bayern)": "095720000000", + "Uttenreuth (Erlangen-Höchstadt - Bayern)": "095720000000", + "Großenseebach (Erlangen-Höchstadt - Bayern)": "095720000000", + "Heßdorf (Erlangen-Höchstadt - Bayern)": "095720000000", + "Birkach (Erlangen-Höchstadt - Bayern)": "095720000000", + "Buckenhofer Forst (Erlangen-Höchstadt - Bayern)": "095720000000", + "Dormitzer Forst (Erlangen-Höchstadt - Bayern)": "095720000000", + "Erlenstegener Forst (Erlangen-Höchstadt - Bayern)": "095720000000", + "Forst Tennenlohe (Erlangen-Höchstadt - Bayern)": "095720000000", + "Geschaidt (Erlangen-Höchstadt - Bayern)": "095720000000", + "Kalchreuther Forst (Erlangen-Höchstadt - Bayern)": "095720000000", + "Kraftshofer Forst (Erlangen-Höchstadt - Bayern)": "095720000000", + "Mark (Erlangen-Höchstadt - Bayern)": "095720000000", + "Neunhofer Forst (Erlangen-Höchstadt - Bayern)": "095720000000", + "Ammerndorf, M (Fürth - Bayern)": "095730000000", + "Cadolzburg, M (Fürth - Bayern)": "095730000000", + "Großhabersdorf (Fürth - Bayern)": "095730000000", + "Langenzenn, St (Fürth - Bayern)": "095730000000", + "Oberasbach, St (Fürth - Bayern)": "095730000000", + "Puschendorf (Fürth - Bayern)": "095730000000", + "Roßtal, M (Fürth - Bayern)": "095730000000", + "Stein, St (Fürth - Bayern)": "095730000000", + "Wilhermsdorf, M (Fürth - Bayern)": "095730000000", + "Zirndorf, St (Fürth - Bayern)": "095730000000", + "Seukendorf (Fürth - Bayern)": "095730000000", + "Veitsbronn (Fürth - Bayern)": "095730000000", + "Obermichelbach (Fürth - Bayern)": "095730000000", + "Tuchenbach (Fürth - Bayern)": "095730000000", + "Altdorf b.Nürnberg, St (Nürnberger Land - Bayern)": "095740000000", + "Burgthann (Nürnberger Land - Bayern)": "095740000000", + "Feucht, M (Nürnberger Land - Bayern)": "095740000000", + "Hersbruck, St (Nürnberger Land - Bayern)": "095740000000", + "Kirchensittenbach (Nürnberger Land - Bayern)": "095740000000", + "Lauf a.d.Pegnitz, St (Nürnberger Land - Bayern)": "095740000000", + "Leinburg (Nürnberger Land - Bayern)": "095740000000", + "Neuhaus a.d.Pegnitz, M (Nürnberger Land - Bayern)": "095740000000", + "Neunkirchen a.Sand (Nürnberger Land - Bayern)": "095740000000", + "Ottensoos (Nürnberger Land - Bayern)": "095740000000", + "Pommelsbrunn (Nürnberger Land - Bayern)": "095740000000", + "Reichenschwand (Nürnberger Land - Bayern)": "095740000000", + "Röthenbach a.d.Pegnitz, St (Nürnberger Land - Bayern)": "095740000000", + "Rückersdorf (Nürnberger Land - Bayern)": "095740000000", + "Schnaittach, M (Nürnberger Land - Bayern)": "095740000000", + "Schwaig b.Nürnberg (Nürnberger Land - Bayern)": "095740000000", + "Schwarzenbruck (Nürnberger Land - Bayern)": "095740000000", + "Simmelsdorf (Nürnberger Land - Bayern)": "095740000000", + "Winkelhaid (Nürnberger Land - Bayern)": "095740000000", + "Hartenstein (Nürnberger Land - Bayern)": "095740000000", + "Velden, St (Nürnberger Land - Bayern)": "095740000000", + "Vorra (Nürnberger Land - Bayern)": "095740000000", + "Alfeld (Nürnberger Land - Bayern)": "095740000000", + "Happurg (Nürnberger Land - Bayern)": "095740000000", + "Engelthal (Nürnberger Land - Bayern)": "095740000000", + "Henfenfeld (Nürnberger Land - Bayern)": "095740000000", + "Offenhausen (Nürnberger Land - Bayern)": "095740000000", + "Behringersdorfer Forst (Nürnberger Land - Bayern)": "095740000000", + "Brunn (Nürnberger Land - Bayern)": "095740000000", + "Engelthaler Forst (Nürnberger Land - Bayern)": "095740000000", + "Feuchter Forst (Nürnberger Land - Bayern)": "095740000000", + "Fischbach (Nürnberger Land - Bayern)": "095740000000", + "Forsthof (Nürnberger Land - Bayern)": "095740000000", + "Günthersbühler Forst (Nürnberger Land - Bayern)": "095740000000", + "Haimendorfer Forst (Nürnberger Land - Bayern)": "095740000000", + "Laufamholzer Forst (Nürnberger Land - Bayern)": "095740000000", + "Rückersdorfer Forst (Nürnberger Land - Bayern)": "095740000000", + "Schönberg (Nürnberger Land - Bayern)": "095740000000", + "Zerzabelshofer Forst (Nürnberger Land - Bayern)": "095740000000", + "Bad Windsheim, St (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Burghaslach, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Dietersheim (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Emskirchen, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Ipsheim, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Markt Erlbach, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Neustadt a.d.Aisch, St (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Obernzenn, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Langenfeld (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Markt Bibart, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Markt Taschendorf, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Oberscheinfeld, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Scheinfeld, St (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Sugenheim, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Ergersheim (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Gollhofen (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Hemmersheim (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Ippesheim, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Markt Nordheim, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Oberickelsheim (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Simmershofen (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Uffenheim, St (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Weigenheim (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Hagenbüchach (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Wilhelmsdorf (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Baudenbach, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Diespeck (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Gutenstetten (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Münchsteinach (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Dachsbach, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Gerhardshofen (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Uehlfeld, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Burgbernheim, St (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Gallmersgarten (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Illesheim (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Marktbergel, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Neuhof a.d.Zenn, M (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Trautskirchen (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Osing (Neustadt an der Aisch-Bad Windsheim - Bayern)": "095750000000", + "Abenberg, St (Roth - Bayern)": "095760000000", + "Allersberg, M (Roth - Bayern)": "095760000000", + "Büchenbach (Roth - Bayern)": "095760000000", + "Georgensgmünd (Roth - Bayern)": "095760000000", + "Greding, St (Roth - Bayern)": "095760000000", + "Heideck, St (Roth - Bayern)": "095760000000", + "Hilpoltstein, St (Roth - Bayern)": "095760000000", + "Kammerstein (Roth - Bayern)": "095760000000", + "Schwanstetten, M (Roth - Bayern)": "095760000000", + "Rednitzhembach (Roth - Bayern)": "095760000000", + "Röttenbach (Roth - Bayern)": "095760000000", + "Rohr (Roth - Bayern)": "095760000000", + "Roth, St (Roth - Bayern)": "095760000000", + "Spalt, St (Roth - Bayern)": "095760000000", + "Thalmässing, M (Roth - Bayern)": "095760000000", + "Wendelstein, M (Roth - Bayern)": "095760000000", + "Abenberger Wald (Roth - Bayern)": "095760000000", + "Dechenwald (Roth - Bayern)": "095760000000", + "Forst Kleinschwarzenlohe (Roth - Bayern)": "095760000000", + "Heidenberg (Roth - Bayern)": "095760000000", + "Soos (Roth - Bayern)": "095760000000", + "Muhr a.See (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Gunzenhausen, St (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Langenaltheim (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Pappenheim, St (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Pleinfeld, M (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Polsingen (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Solnhofen (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Treuchtlingen, St (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Weißenburg i.Bay., GKSt (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Absberg, M (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Haundorf (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Pfofeld (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Theilenhofen (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Alesheim (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Dittenheim (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Markt Berolzheim, M (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Meinheim (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Ellingen, St (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Ettenstatt (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Höttingen (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Bergen (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Burgsalach (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Nennslingen, M (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Raitenbuch (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Gnotzheim, M (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Heidenheim, M (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Westheim (Weißenburg-Gunzenhausen - Bayern)": "095770000000", + "Aschaffenburg": "096610000000", + "Schweinfurt": "096620000000", + "Würzburg": "096630000000", + "Alzenau, St (Aschaffenburg - Bayern)": "096710000000", + "Bessenbach (Aschaffenburg - Bayern)": "096710000000", + "Karlstein a.Main (Aschaffenburg - Bayern)": "096710000000", + "Geiselbach (Aschaffenburg - Bayern)": "096710000000", + "Glattbach (Aschaffenburg - Bayern)": "096710000000", + "Goldbach, M (Aschaffenburg - Bayern)": "096710000000", + "Großostheim, M (Aschaffenburg - Bayern)": "096710000000", + "Haibach (Aschaffenburg - Bayern)": "096710000000", + "Hösbach, M (Aschaffenburg - Bayern)": "096710000000", + "Johannesberg (Aschaffenburg - Bayern)": "096710000000", + "Kahl a.Main (Aschaffenburg - Bayern)": "096710000000", + "Kleinostheim (Aschaffenburg - Bayern)": "096710000000", + "Laufach (Aschaffenburg - Bayern)": "096710000000", + "Mainaschaff (Aschaffenburg - Bayern)": "096710000000", + "Mömbris, M (Aschaffenburg - Bayern)": "096710000000", + "Rothenbuch (Aschaffenburg - Bayern)": "096710000000", + "Sailauf (Aschaffenburg - Bayern)": "096710000000", + "Stockstadt a.Main, M (Aschaffenburg - Bayern)": "096710000000", + "Waldaschaff (Aschaffenburg - Bayern)": "096710000000", + "Weibersbrunn (Aschaffenburg - Bayern)": "096710000000", + "Heigenbrücken (Aschaffenburg - Bayern)": "096710000000", + "Heinrichsthal (Aschaffenburg - Bayern)": "096710000000", + "Heimbuchenthal (Aschaffenburg - Bayern)": "096710000000", + "Mespelbrunn (Aschaffenburg - Bayern)": "096710000000", + "Dammbach (Aschaffenburg - Bayern)": "096710000000", + "Blankenbach (Aschaffenburg - Bayern)": "096710000000", + "Kleinkahl (Aschaffenburg - Bayern)": "096710000000", + "Krombach (Aschaffenburg - Bayern)": "096710000000", + "Schöllkrippen, M (Aschaffenburg - Bayern)": "096710000000", + "Sommerkahl (Aschaffenburg - Bayern)": "096710000000", + "Westerngrund (Aschaffenburg - Bayern)": "096710000000", + "Wiesen (Aschaffenburg - Bayern)": "096710000000", + "Forst Hain i.Spessart (Aschaffenburg - Bayern)": "096710000000", + "Heinrichsthaler Forst (Aschaffenburg - Bayern)": "096710000000", + "Rohrbrunner Forst (Aschaffenburg - Bayern)": "096710000000", + "Rothenbucher Forst (Aschaffenburg - Bayern)": "096710000000", + "Sailaufer Forst (Aschaffenburg - Bayern)": "096710000000", + "Schöllkrippener Forst (Aschaffenburg - Bayern)": "096710000000", + "Waldaschaffer Forst (Aschaffenburg - Bayern)": "096710000000", + "Wiesener Forst (Aschaffenburg - Bayern)": "096710000000", + "Bad Bocklet, M (Bad Kissingen - Bayern)": "096720000000", + "Bad Brückenau, St (Bad Kissingen - Bayern)": "096720000000", + "Bad Kissingen, GKSt (Bad Kissingen - Bayern)": "096720000000", + "Burkardroth, M (Bad Kissingen - Bayern)": "096720000000", + "Hammelburg, St (Bad Kissingen - Bayern)": "096720000000", + "Motten (Bad Kissingen - Bayern)": "096720000000", + "Münnerstadt, St (Bad Kissingen - Bayern)": "096720000000", + "Nüdlingen (Bad Kissingen - Bayern)": "096720000000", + "Oberthulba, M (Bad Kissingen - Bayern)": "096720000000", + "Oerlenbach (Bad Kissingen - Bayern)": "096720000000", + "Wartmannsroth (Bad Kissingen - Bayern)": "096720000000", + "Wildflecken, M (Bad Kissingen - Bayern)": "096720000000", + "Zeitlofs, M (Bad Kissingen - Bayern)": "096720000000", + "Geroda, M (Bad Kissingen - Bayern)": "096720000000", + "Oberleichtersbach (Bad Kissingen - Bayern)": "096720000000", + "Riedenberg (Bad Kissingen - Bayern)": "096720000000", + "Schondra, M (Bad Kissingen - Bayern)": "096720000000", + "Elfershausen, M (Bad Kissingen - Bayern)": "096720000000", + "Fuchsstadt (Bad Kissingen - Bayern)": "096720000000", + "Aura a.d.Saale (Bad Kissingen - Bayern)": "096720000000", + "Euerdorf, M (Bad Kissingen - Bayern)": "096720000000", + "Ramsthal (Bad Kissingen - Bayern)": "096720000000", + "Sulzthal, M (Bad Kissingen - Bayern)": "096720000000", + "Maßbach, M (Bad Kissingen - Bayern)": "096720000000", + "Rannungen (Bad Kissingen - Bayern)": "096720000000", + "Thundorf i.UFr. (Bad Kissingen - Bayern)": "096720000000", + "Dreistelzer Forst (Bad Kissingen - Bayern)": "096720000000", + "Forst Detter-Süd (Bad Kissingen - Bayern)": "096720000000", + "Geiersnest-Ost (Bad Kissingen - Bayern)": "096720000000", + "Geiersnest-West (Bad Kissingen - Bayern)": "096720000000", + "Großer Auersberg (Bad Kissingen - Bayern)": "096720000000", + "Kälberberg (Bad Kissingen - Bayern)": "096720000000", + "Mottener Forst-Süd (Bad Kissingen - Bayern)": "096720000000", + "Neuwirtshauser Forst (Bad Kissingen - Bayern)": "096720000000", + "Omerz u. Roter Berg (Bad Kissingen - Bayern)": "096720000000", + "Römershager Forst-Nord (Bad Kissingen - Bayern)": "096720000000", + "Römershager Forst-Ost (Bad Kissingen - Bayern)": "096720000000", + "Roßbacher Forst (Bad Kissingen - Bayern)": "096720000000", + "Waldfensterer Forst (Bad Kissingen - Bayern)": "096720000000", + "Bad Neustadt a.d.Saale, St (Rhön-Grabfeld - Bayern)": "096730000000", + "Bastheim (Rhön-Grabfeld - Bayern)": "096730000000", + "Bischofsheim i.d.Rhön, St (Rhön-Grabfeld - Bayern)": "096730000000", + "Bad Königshofen i.Grabfeld, St (Rhön-Grabfeld - Bayern)": "096730000000", + "Oberelsbach, M (Rhön-Grabfeld - Bayern)": "096730000000", + "Sandberg (Rhön-Grabfeld - Bayern)": "096730000000", + "Hendungen (Rhön-Grabfeld - Bayern)": "096730000000", + "Mellrichstadt, St (Rhön-Grabfeld - Bayern)": "096730000000", + "Oberstreu (Rhön-Grabfeld - Bayern)": "096730000000", + "Stockheim (Rhön-Grabfeld - Bayern)": "096730000000", + "Aubstadt (Rhön-Grabfeld - Bayern)": "096730000000", + "Großbardorf (Rhön-Grabfeld - Bayern)": "096730000000", + "Herbstadt (Rhön-Grabfeld - Bayern)": "096730000000", + "Höchheim (Rhön-Grabfeld - Bayern)": "096730000000", + "Sulzdorf a.d.Lederhecke (Rhön-Grabfeld - Bayern)": "096730000000", + "Sulzfeld (Rhön-Grabfeld - Bayern)": "096730000000", + "Trappstadt, M (Rhön-Grabfeld - Bayern)": "096730000000", + "Hohenroth (Rhön-Grabfeld - Bayern)": "096730000000", + "Niederlauer (Rhön-Grabfeld - Bayern)": "096730000000", + "Rödelmaier (Rhön-Grabfeld - Bayern)": "096730000000", + "Salz (Rhön-Grabfeld - Bayern)": "096730000000", + "Schönau a.d.Brend (Rhön-Grabfeld - Bayern)": "096730000000", + "Strahlungen (Rhön-Grabfeld - Bayern)": "096730000000", + "Burglauer (Rhön-Grabfeld - Bayern)": "096730000000", + "Fladungen, St (Rhön-Grabfeld - Bayern)": "096730000000", + "Hausen (Rhön-Grabfeld - Bayern)": "096730000000", + "Nordheim v.d.Rhön (Rhön-Grabfeld - Bayern)": "096730000000", + "Heustreu (Rhön-Grabfeld - Bayern)": "096730000000", + "Hollstadt (Rhön-Grabfeld - Bayern)": "096730000000", + "Unsleben (Rhön-Grabfeld - Bayern)": "096730000000", + "Wollbach (Rhön-Grabfeld - Bayern)": "096730000000", + "Ostheim v.d.Rhön, St (Rhön-Grabfeld - Bayern)": "096730000000", + "Sondheim v.d.Rhön (Rhön-Grabfeld - Bayern)": "096730000000", + "Willmars (Rhön-Grabfeld - Bayern)": "096730000000", + "Großeibstadt (Rhön-Grabfeld - Bayern)": "096730000000", + "Saal a.d.Saale, M (Rhön-Grabfeld - Bayern)": "096730000000", + "Wülfershausen a.d.Saale (Rhön-Grabfeld - Bayern)": "096730000000", + "Bundorfer Forst (Rhön-Grabfeld - Bayern)": "096730000000", + "Burgwallbacher Forst (Rhön-Grabfeld - Bayern)": "096730000000", + "Forst Schmalwasser-Nord (Rhön-Grabfeld - Bayern)": "096730000000", + "Forst Schmalwasser-Süd (Rhön-Grabfeld - Bayern)": "096730000000", + "Mellrichstadter Forst (Rhön-Grabfeld - Bayern)": "096730000000", + "Steinacher Forst r.d.Saale (Rhön-Grabfeld - Bayern)": "096730000000", + "Sulzfelder Forst (Rhön-Grabfeld - Bayern)": "096730000000", + "Weigler (Rhön-Grabfeld - Bayern)": "096730000000", + "Eltmann, St (Haßberge - Bayern)": "096740000000", + "Haßfurt, St (Haßberge - Bayern)": "096740000000", + "Oberaurach (Haßberge - Bayern)": "096740000000", + "Knetzgau (Haßberge - Bayern)": "096740000000", + "Königsberg i.Bay., St (Haßberge - Bayern)": "096740000000", + "Maroldsweisach, M (Haßberge - Bayern)": "096740000000", + "Rauhenebrach (Haßberge - Bayern)": "096740000000", + "Sand a.Main (Haßberge - Bayern)": "096740000000", + "Untermerzbach (Haßberge - Bayern)": "096740000000", + "Zeil a.Main, St (Haßberge - Bayern)": "096740000000", + "Breitbrunn (Haßberge - Bayern)": "096740000000", + "Ebelsbach (Haßberge - Bayern)": "096740000000", + "Kirchlauter (Haßberge - Bayern)": "096740000000", + "Stettfeld (Haßberge - Bayern)": "096740000000", + "Ebern, St (Haßberge - Bayern)": "096740000000", + "Pfarrweisach (Haßberge - Bayern)": "096740000000", + "Rentweinsdorf, M (Haßberge - Bayern)": "096740000000", + "Aidhausen (Haßberge - Bayern)": "096740000000", + "Bundorf (Haßberge - Bayern)": "096740000000", + "Burgpreppach, M (Haßberge - Bayern)": "096740000000", + "Hofheim i.UFr., St (Haßberge - Bayern)": "096740000000", + "Riedbach (Haßberge - Bayern)": "096740000000", + "Ermershausen (Haßberge - Bayern)": "096740000000", + "Gädheim (Haßberge - Bayern)": "096740000000", + "Theres (Haßberge - Bayern)": "096740000000", + "Wonfurt (Haßberge - Bayern)": "096740000000", + "Dettelbach, St (Kitzingen - Bayern)": "096750000000", + "Geiselwind, M (Kitzingen - Bayern)": "096750000000", + "Kitzingen, GKSt (Kitzingen - Bayern)": "096750000000", + "Mainbernheim, St (Kitzingen - Bayern)": "096750000000", + "Prichsenstadt, St (Kitzingen - Bayern)": "096750000000", + "Schwarzach a.Main, M (Kitzingen - Bayern)": "096750000000", + "Abtswind, M (Kitzingen - Bayern)": "096750000000", + "Castell (Kitzingen - Bayern)": "096750000000", + "Rüdenhausen, M (Kitzingen - Bayern)": "096750000000", + "Wiesentheid, M (Kitzingen - Bayern)": "096750000000", + "Großlangheim, M (Kitzingen - Bayern)": "096750000000", + "Kleinlangheim, M (Kitzingen - Bayern)": "096750000000", + "Wiesenbronn (Kitzingen - Bayern)": "096750000000", + "Iphofen, St (Kitzingen - Bayern)": "096750000000", + "Markt Einersheim, M (Kitzingen - Bayern)": "096750000000", + "Rödelsee (Kitzingen - Bayern)": "096750000000", + "Willanzheim, M (Kitzingen - Bayern)": "096750000000", + "Albertshofen (Kitzingen - Bayern)": "096750000000", + "Biebelried (Kitzingen - Bayern)": "096750000000", + "Buchbrunn (Kitzingen - Bayern)": "096750000000", + "Mainstockheim (Kitzingen - Bayern)": "096750000000", + "Sulzfeld a.Main (Kitzingen - Bayern)": "096750000000", + "Marktbreit, St (Kitzingen - Bayern)": "096750000000", + "Marktsteft, St (Kitzingen - Bayern)": "096750000000", + "Martinsheim (Kitzingen - Bayern)": "096750000000", + "Obernbreit, M (Kitzingen - Bayern)": "096750000000", + "Segnitz (Kitzingen - Bayern)": "096750000000", + "Seinsheim, M (Kitzingen - Bayern)": "096750000000", + "Nordheim a.Main (Kitzingen - Bayern)": "096750000000", + "Sommerach (Kitzingen - Bayern)": "096750000000", + "Volkach, St (Kitzingen - Bayern)": "096750000000", + "Amorbach, St (Miltenberg - Bayern)": "096760000000", + "Collenberg (Miltenberg - Bayern)": "096760000000", + "Dorfprozelten (Miltenberg - Bayern)": "096760000000", + "Eichenbühl (Miltenberg - Bayern)": "096760000000", + "Elsenfeld, M (Miltenberg - Bayern)": "096760000000", + "Erlenbach a.Main, St (Miltenberg - Bayern)": "096760000000", + "Eschau, M (Miltenberg - Bayern)": "096760000000", + "Faulbach (Miltenberg - Bayern)": "096760000000", + "Großheubach, M (Miltenberg - Bayern)": "096760000000", + "Großwallstadt (Miltenberg - Bayern)": "096760000000", + "Kirchzell, M (Miltenberg - Bayern)": "096760000000", + "Klingenberg a.Main, St (Miltenberg - Bayern)": "096760000000", + "Leidersbach (Miltenberg - Bayern)": "096760000000", + "Miltenberg, St (Miltenberg - Bayern)": "096760000000", + "Mömlingen (Miltenberg - Bayern)": "096760000000", + "Niedernberg (Miltenberg - Bayern)": "096760000000", + "Obernburg a.Main, St (Miltenberg - Bayern)": "096760000000", + "Schneeberg, M (Miltenberg - Bayern)": "096760000000", + "Sulzbach a.Main, M (Miltenberg - Bayern)": "096760000000", + "Weilbach, M (Miltenberg - Bayern)": "096760000000", + "Wörth a.Main, St (Miltenberg - Bayern)": "096760000000", + "Bürgstadt, M (Miltenberg - Bayern)": "096760000000", + "Neunkirchen (Miltenberg - Bayern)": "096760000000", + "Kleinheubach, M (Miltenberg - Bayern)": "096760000000", + "Laudenbach (Miltenberg - Bayern)": "096760000000", + "Rüdenau (Miltenberg - Bayern)": "096760000000", + "Hausen (Miltenberg - Bayern)": "096760000000", + "Kleinwallstadt, M (Miltenberg - Bayern)": "096760000000", + "Mönchberg, M (Miltenberg - Bayern)": "096760000000", + "Röllbach (Miltenberg - Bayern)": "096760000000", + "Altenbuch (Miltenberg - Bayern)": "096760000000", + "Stadtprozelten, St (Miltenberg - Bayern)": "096760000000", + "Forstwald (Miltenberg - Bayern)": "096760000000", + "Hohe Wart (Miltenberg - Bayern)": "096760000000", + "Arnstein, St (Main-Spessart - Bayern)": "096770000000", + "Eußenheim (Main-Spessart - Bayern)": "096770000000", + "Frammersbach, M (Main-Spessart - Bayern)": "096770000000", + "Gemünden a.Main, St (Main-Spessart - Bayern)": "096770000000", + "Karlstadt, St (Main-Spessart - Bayern)": "096770000000", + "Triefenstein, M (Main-Spessart - Bayern)": "096770000000", + "Lohr a.Main, St (Main-Spessart - Bayern)": "096770000000", + "Marktheidenfeld, St (Main-Spessart - Bayern)": "096770000000", + "Rieneck, St (Main-Spessart - Bayern)": "096770000000", + "Hasloch (Main-Spessart - Bayern)": "096770000000", + "Kreuzwertheim, M (Main-Spessart - Bayern)": "096770000000", + "Schollbrunn (Main-Spessart - Bayern)": "096770000000", + "Birkenfeld (Main-Spessart - Bayern)": "096770000000", + "Bischbrunn (Main-Spessart - Bayern)": "096770000000", + "Erlenbach b.Marktheidenfeld (Main-Spessart - Bayern)": "096770000000", + "Esselbach (Main-Spessart - Bayern)": "096770000000", + "Hafenlohr (Main-Spessart - Bayern)": "096770000000", + "Karbach, M (Main-Spessart - Bayern)": "096770000000", + "Roden (Main-Spessart - Bayern)": "096770000000", + "Rothenfels, St (Main-Spessart - Bayern)": "096770000000", + "Urspringen (Main-Spessart - Bayern)": "096770000000", + "Aura i.Sinngrund (Main-Spessart - Bayern)": "096770000000", + "Burgsinn, M (Main-Spessart - Bayern)": "096770000000", + "Fellen (Main-Spessart - Bayern)": "096770000000", + "Mittelsinn (Main-Spessart - Bayern)": "096770000000", + "Obersinn, M (Main-Spessart - Bayern)": "096770000000", + "Gössenheim (Main-Spessart - Bayern)": "096770000000", + "Gräfendorf (Main-Spessart - Bayern)": "096770000000", + "Karsbach (Main-Spessart - Bayern)": "096770000000", + "Neuendorf (Main-Spessart - Bayern)": "096770000000", + "Neustadt a.Main (Main-Spessart - Bayern)": "096770000000", + "Rechtenbach (Main-Spessart - Bayern)": "096770000000", + "Steinfeld (Main-Spessart - Bayern)": "096770000000", + "Himmelstadt (Main-Spessart - Bayern)": "096770000000", + "Retzstadt (Main-Spessart - Bayern)": "096770000000", + "Thüngen, M (Main-Spessart - Bayern)": "096770000000", + "Zellingen, M (Main-Spessart - Bayern)": "096770000000", + "Neuhütten (Main-Spessart - Bayern)": "096770000000", + "Partenstein (Main-Spessart - Bayern)": "096770000000", + "Wiesthal (Main-Spessart - Bayern)": "096770000000", + "Burgjoß (Main-Spessart - Bayern)": "096770000000", + "Forst Aura (Main-Spessart - Bayern)": "096770000000", + "Forst Lohrerstraße (Main-Spessart - Bayern)": "096770000000", + "Frammersbacher Forst (Main-Spessart - Bayern)": "096770000000", + "Fürstl. Löwenstein'scher Park (Main-Spessart - Bayern)": "096770000000", + "Haurain (Main-Spessart - Bayern)": "096770000000", + "Herrnwald (Main-Spessart - Bayern)": "096770000000", + "Langenprozeltener Forst (Main-Spessart - Bayern)": "096770000000", + "Partensteiner Forst (Main-Spessart - Bayern)": "096770000000", + "Ruppertshüttener Forst (Main-Spessart - Bayern)": "096770000000", + "Bergrheinfeld (Schweinfurt - Bayern)": "096780000000", + "Dittelbrunn (Schweinfurt - Bayern)": "096780000000", + "Euerbach (Schweinfurt - Bayern)": "096780000000", + "Geldersheim (Schweinfurt - Bayern)": "096780000000", + "Gochsheim (Schweinfurt - Bayern)": "096780000000", + "Grafenrheinfeld (Schweinfurt - Bayern)": "096780000000", + "Grettstadt (Schweinfurt - Bayern)": "096780000000", + "Kolitzheim (Schweinfurt - Bayern)": "096780000000", + "Niederwerrn (Schweinfurt - Bayern)": "096780000000", + "Poppenhausen (Schweinfurt - Bayern)": "096780000000", + "Röthlein (Schweinfurt - Bayern)": "096780000000", + "Schonungen (Schweinfurt - Bayern)": "096780000000", + "Schwebheim (Schweinfurt - Bayern)": "096780000000", + "Sennfeld (Schweinfurt - Bayern)": "096780000000", + "Stadtlauringen, M (Schweinfurt - Bayern)": "096780000000", + "Üchtelhausen (Schweinfurt - Bayern)": "096780000000", + "Waigolshausen (Schweinfurt - Bayern)": "096780000000", + "Wasserlosen (Schweinfurt - Bayern)": "096780000000", + "Werneck, M (Schweinfurt - Bayern)": "096780000000", + "Dingolshausen (Schweinfurt - Bayern)": "096780000000", + "Donnersdorf (Schweinfurt - Bayern)": "096780000000", + "Frankenwinheim (Schweinfurt - Bayern)": "096780000000", + "Gerolzhofen, St (Schweinfurt - Bayern)": "096780000000", + "Lülsfeld (Schweinfurt - Bayern)": "096780000000", + "Michelau i.Steigerwald (Schweinfurt - Bayern)": "096780000000", + "Oberschwarzach, M (Schweinfurt - Bayern)": "096780000000", + "Sulzheim (Schweinfurt - Bayern)": "096780000000", + "Schwanfeld (Schweinfurt - Bayern)": "096780000000", + "Wipfeld (Schweinfurt - Bayern)": "096780000000", + "Bürgerwald (Schweinfurt - Bayern)": "096780000000", + "Geiersberg (Schweinfurt - Bayern)": "096780000000", + "Hundelshausen (Schweinfurt - Bayern)": "096780000000", + "Nonnenkloster (Schweinfurt - Bayern)": "096780000000", + "Stollbergerforst (Schweinfurt - Bayern)": "096780000000", + "Vollburg (Schweinfurt - Bayern)": "096780000000", + "Wustvieler Forst (Schweinfurt - Bayern)": "096780000000", + "Eisingen (Würzburg - Bayern)": "096790000000", + "Gaukönigshofen (Würzburg - Bayern)": "096790000000", + "Gerbrunn (Würzburg - Bayern)": "096790000000", + "Güntersleben (Würzburg - Bayern)": "096790000000", + "Hausen b.Würzburg (Würzburg - Bayern)": "096790000000", + "Höchberg, M (Würzburg - Bayern)": "096790000000", + "Kleinrinderfeld (Würzburg - Bayern)": "096790000000", + "Kürnach (Würzburg - Bayern)": "096790000000", + "Neubrunn, M (Würzburg - Bayern)": "096790000000", + "Ochsenfurt, St (Würzburg - Bayern)": "096790000000", + "Randersacker, M (Würzburg - Bayern)": "096790000000", + "Reichenberg, M (Würzburg - Bayern)": "096790000000", + "Rimpar, M (Würzburg - Bayern)": "096790000000", + "Rottendorf (Würzburg - Bayern)": "096790000000", + "Theilheim (Würzburg - Bayern)": "096790000000", + "Thüngersheim (Würzburg - Bayern)": "096790000000", + "Leinach (Würzburg - Bayern)": "096790000000", + "Unterpleichfeld (Würzburg - Bayern)": "096790000000", + "Veitshöchheim (Würzburg - Bayern)": "096790000000", + "Waldbrunn (Würzburg - Bayern)": "096790000000", + "Waldbüttelbrunn (Würzburg - Bayern)": "096790000000", + "Zell a.Main, M (Würzburg - Bayern)": "096790000000", + "Aub, St (Würzburg - Bayern)": "096790000000", + "Gelchsheim, M (Würzburg - Bayern)": "096790000000", + "Sonderhofen (Würzburg - Bayern)": "096790000000", + "Bergtheim (Würzburg - Bayern)": "096790000000", + "Oberpleichfeld (Würzburg - Bayern)": "096790000000", + "Eibelstadt, St (Würzburg - Bayern)": "096790000000", + "Frickenhausen a.Main, M (Würzburg - Bayern)": "096790000000", + "Sommerhausen, M (Würzburg - Bayern)": "096790000000", + "Winterhausen, M (Würzburg - Bayern)": "096790000000", + "Estenfeld (Würzburg - Bayern)": "096790000000", + "Eisenheim, M (Würzburg - Bayern)": "096790000000", + "Prosselsheim (Würzburg - Bayern)": "096790000000", + "Bütthard, M (Würzburg - Bayern)": "096790000000", + "Giebelstadt, M (Würzburg - Bayern)": "096790000000", + "Helmstadt, M (Würzburg - Bayern)": "096790000000", + "Holzkirchen (Würzburg - Bayern)": "096790000000", + "Remlingen, M (Würzburg - Bayern)": "096790000000", + "Uettingen (Würzburg - Bayern)": "096790000000", + "Geroldshausen (Würzburg - Bayern)": "096790000000", + "Kirchheim (Würzburg - Bayern)": "096790000000", + "Kist (Würzburg - Bayern)": "096790000000", + "Altertheim (Würzburg - Bayern)": "096790000000", + "Erlabrunn (Würzburg - Bayern)": "096790000000", + "Margetshöchheim (Würzburg - Bayern)": "096790000000", + "Bieberehren (Würzburg - Bayern)": "096790000000", + "Riedenheim (Würzburg - Bayern)": "096790000000", + "Röttingen, St (Würzburg - Bayern)": "096790000000", + "Tauberrettersheim (Würzburg - Bayern)": "096790000000", + "Greußenheim (Würzburg - Bayern)": "096790000000", + "Hettstadt (Würzburg - Bayern)": "096790000000", + "Gramschatzer Wald (Würzburg - Bayern)": "096790000000", + "Guttenberger Wald (Würzburg - Bayern)": "096790000000", + "Irtenberger Wald (Würzburg - Bayern)": "096790000000", + "Augsburg": "097610000000", + "Kaufbeuren": "097620000000", + "Kempten (Allgäu)": "097630000000", + "Memmingen": "097640000000", + "Affing (Aichach-Friedberg - Bayern)": "097710000000", + "Aichach, St (Aichach-Friedberg - Bayern)": "097710000000", + "Friedberg, St (Aichach-Friedberg - Bayern)": "097710000000", + "Hollenbach (Aichach-Friedberg - Bayern)": "097710000000", + "Inchenhofen, M (Aichach-Friedberg - Bayern)": "097710000000", + "Kissing (Aichach-Friedberg - Bayern)": "097710000000", + "Merching (Aichach-Friedberg - Bayern)": "097710000000", + "Rehling (Aichach-Friedberg - Bayern)": "097710000000", + "Ried (Aichach-Friedberg - Bayern)": "097710000000", + "Aindling, M (Aichach-Friedberg - Bayern)": "097710000000", + "Petersdorf (Aichach-Friedberg - Bayern)": "097710000000", + "Todtenweis (Aichach-Friedberg - Bayern)": "097710000000", + "Kühbach, M (Aichach-Friedberg - Bayern)": "097710000000", + "Schiltberg (Aichach-Friedberg - Bayern)": "097710000000", + "Adelzhausen (Aichach-Friedberg - Bayern)": "097710000000", + "Dasing (Aichach-Friedberg - Bayern)": "097710000000", + "Eurasburg (Aichach-Friedberg - Bayern)": "097710000000", + "Obergriesbach (Aichach-Friedberg - Bayern)": "097710000000", + "Sielenbach (Aichach-Friedberg - Bayern)": "097710000000", + "Mering, M (Aichach-Friedberg - Bayern)": "097710000000", + "Schmiechen (Aichach-Friedberg - Bayern)": "097710000000", + "Steindorf (Aichach-Friedberg - Bayern)": "097710000000", + "Pöttmes, M (Aichach-Friedberg - Bayern)": "097710000000", + "Baar (Schwaben) (Aichach-Friedberg - Bayern)": "097710000000", + "Adelsried (Augsburg - Bayern)": "097720000000", + "Altenmünster (Augsburg - Bayern)": "097720000000", + "Aystetten (Augsburg - Bayern)": "097720000000", + "Biberbach, M (Augsburg - Bayern)": "097720000000", + "Bobingen, St (Augsburg - Bayern)": "097720000000", + "Diedorf, M (Augsburg - Bayern)": "097720000000", + "Dinkelscherben, M (Augsburg - Bayern)": "097720000000", + "Fischach, M (Augsburg - Bayern)": "097720000000", + "Gablingen (Augsburg - Bayern)": "097720000000", + "Gersthofen, St (Augsburg - Bayern)": "097720000000", + "Graben (Augsburg - Bayern)": "097720000000", + "Horgau (Augsburg - Bayern)": "097720000000", + "Königsbrunn, St (Augsburg - Bayern)": "097720000000", + "Kutzenhausen (Augsburg - Bayern)": "097720000000", + "Langweid a.Lech (Augsburg - Bayern)": "097720000000", + "Meitingen, M (Augsburg - Bayern)": "097720000000", + "Neusäß, St (Augsburg - Bayern)": "097720000000", + "Schwabmünchen, St (Augsburg - Bayern)": "097720000000", + "Stadtbergen, St (Augsburg - Bayern)": "097720000000", + "Thierhaupten, M (Augsburg - Bayern)": "097720000000", + "Wehringen (Augsburg - Bayern)": "097720000000", + "Zusmarshausen, M (Augsburg - Bayern)": "097720000000", + "Allmannshofen (Augsburg - Bayern)": "097720000000", + "Ehingen (Augsburg - Bayern)": "097720000000", + "Ellgau (Augsburg - Bayern)": "097720000000", + "Kühlenthal (Augsburg - Bayern)": "097720000000", + "Nordendorf (Augsburg - Bayern)": "097720000000", + "Westendorf (Augsburg - Bayern)": "097720000000", + "Bonstetten (Augsburg - Bayern)": "097720000000", + "Emersacker (Augsburg - Bayern)": "097720000000", + "Heretsried (Augsburg - Bayern)": "097720000000", + "Welden, M (Augsburg - Bayern)": "097720000000", + "Gessertshausen (Augsburg - Bayern)": "097720000000", + "Ustersbach (Augsburg - Bayern)": "097720000000", + "Langenneufnach (Augsburg - Bayern)": "097720000000", + "Mickhausen (Augsburg - Bayern)": "097720000000", + "Mittelneufnach (Augsburg - Bayern)": "097720000000", + "Scherstetten (Augsburg - Bayern)": "097720000000", + "Walkertshofen (Augsburg - Bayern)": "097720000000", + "Großaitingen (Augsburg - Bayern)": "097720000000", + "Kleinaitingen (Augsburg - Bayern)": "097720000000", + "Oberottmarshausen (Augsburg - Bayern)": "097720000000", + "Klosterlechfeld (Augsburg - Bayern)": "097720000000", + "Untermeitingen (Augsburg - Bayern)": "097720000000", + "Hiltenfingen (Augsburg - Bayern)": "097720000000", + "Langerringen (Augsburg - Bayern)": "097720000000", + "Schmellerforst (Augsburg - Bayern)": "097720000000", + "Bissingen, M (Dillingen an der Donau - Bayern)": "097730000000", + "Buttenwiesen (Dillingen an der Donau - Bayern)": "097730000000", + "Dillingen a.d.Donau, GKSt (Dillingen an der Donau - Bayern)": "097730000000", + "Lauingen (Donau), St (Dillingen an der Donau - Bayern)": "097730000000", + "Bächingen a.d.Brenz (Dillingen an der Donau - Bayern)": "097730000000", + "Gundelfingen a.d.Donau, St (Dillingen an der Donau - Bayern)": "097730000000", + "Haunsheim (Dillingen an der Donau - Bayern)": "097730000000", + "Medlingen (Dillingen an der Donau - Bayern)": "097730000000", + "Bachhagel (Dillingen an der Donau - Bayern)": "097730000000", + "Syrgenstein (Dillingen an der Donau - Bayern)": "097730000000", + "Zöschingen (Dillingen an der Donau - Bayern)": "097730000000", + "Mödingen (Dillingen an der Donau - Bayern)": "097730000000", + "Wittislingen, M (Dillingen an der Donau - Bayern)": "097730000000", + "Ziertheim (Dillingen an der Donau - Bayern)": "097730000000", + "Blindheim (Dillingen an der Donau - Bayern)": "097730000000", + "Höchstädt a.d.Donau, St (Dillingen an der Donau - Bayern)": "097730000000", + "Lutzingen (Dillingen an der Donau - Bayern)": "097730000000", + "Finningen (Dillingen an der Donau - Bayern)": "097730000000", + "Schwenningen (Dillingen an der Donau - Bayern)": "097730000000", + "Binswangen (Dillingen an der Donau - Bayern)": "097730000000", + "Laugna (Dillingen an der Donau - Bayern)": "097730000000", + "Villenbach (Dillingen an der Donau - Bayern)": "097730000000", + "Wertingen, St (Dillingen an der Donau - Bayern)": "097730000000", + "Zusamaltheim (Dillingen an der Donau - Bayern)": "097730000000", + "Aislingen, M (Dillingen an der Donau - Bayern)": "097730000000", + "Glött (Dillingen an der Donau - Bayern)": "097730000000", + "Holzheim (Dillingen an der Donau - Bayern)": "097730000000", + "Ursberg (Günzburg - Bayern)": "097740000000", + "Bibertal (Günzburg - Bayern)": "097740000000", + "Burgau, St (Günzburg - Bayern)": "097740000000", + "Burtenbach, M (Günzburg - Bayern)": "097740000000", + "Günzburg, GKSt (Günzburg - Bayern)": "097740000000", + "Jettingen-Scheppach, M (Günzburg - Bayern)": "097740000000", + "Kammeltal (Günzburg - Bayern)": "097740000000", + "Krumbach (Schwaben), St (Günzburg - Bayern)": "097740000000", + "Leipheim, St (Günzburg - Bayern)": "097740000000", + "Neuburg a.d.Kammel, M (Günzburg - Bayern)": "097740000000", + "Gundremmingen (Günzburg - Bayern)": "097740000000", + "Offingen, M (Günzburg - Bayern)": "097740000000", + "Rettenbach (Günzburg - Bayern)": "097740000000", + "Dürrlauingen (Günzburg - Bayern)": "097740000000", + "Haldenwang (Günzburg - Bayern)": "097740000000", + "Landensberg (Günzburg - Bayern)": "097740000000", + "Röfingen (Günzburg - Bayern)": "097740000000", + "Winterbach (Günzburg - Bayern)": "097740000000", + "Bubesheim (Günzburg - Bayern)": "097740000000", + "Kötz (Günzburg - Bayern)": "097740000000", + "Ellzee (Günzburg - Bayern)": "097740000000", + "Ichenhausen, St (Günzburg - Bayern)": "097740000000", + "Waldstetten, M (Günzburg - Bayern)": "097740000000", + "Aletshausen (Günzburg - Bayern)": "097740000000", + "Breitenthal (Günzburg - Bayern)": "097740000000", + "Deisenhausen (Günzburg - Bayern)": "097740000000", + "Ebershausen (Günzburg - Bayern)": "097740000000", + "Wiesenbach (Günzburg - Bayern)": "097740000000", + "Waltenhausen (Günzburg - Bayern)": "097740000000", + "Balzhausen (Günzburg - Bayern)": "097740000000", + "Münsterhausen, M (Günzburg - Bayern)": "097740000000", + "Thannhausen, St (Günzburg - Bayern)": "097740000000", + "Aichen (Günzburg - Bayern)": "097740000000", + "Ziemetshausen, M (Günzburg - Bayern)": "097740000000", + "Ebershauser-Nattenhauser Wald (Günzburg - Bayern)": "097740000000", + "Winzerwald (Günzburg - Bayern)": "097740000000", + "Bellenberg (Neu-Ulm - Bayern)": "097750000000", + "Illertissen, St (Neu-Ulm - Bayern)": "097750000000", + "Nersingen (Neu-Ulm - Bayern)": "097750000000", + "Neu-Ulm, GKSt (Neu-Ulm - Bayern)": "097750000000", + "Elchingen (Neu-Ulm - Bayern)": "097750000000", + "Roggenburg (Neu-Ulm - Bayern)": "097750000000", + "Senden, St (Neu-Ulm - Bayern)": "097750000000", + "Vöhringen, St (Neu-Ulm - Bayern)": "097750000000", + "Weißenhorn, St (Neu-Ulm - Bayern)": "097750000000", + "Holzheim (Neu-Ulm - Bayern)": "097750000000", + "Pfaffenhofen a.d.Roth, M (Neu-Ulm - Bayern)": "097750000000", + "Altenstadt, M (Neu-Ulm - Bayern)": "097750000000", + "Kellmünz a.d.Iller, M (Neu-Ulm - Bayern)": "097750000000", + "Osterberg (Neu-Ulm - Bayern)": "097750000000", + "Buch, M (Neu-Ulm - Bayern)": "097750000000", + "Oberroth (Neu-Ulm - Bayern)": "097750000000", + "Unterroth (Neu-Ulm - Bayern)": "097750000000", + "Auwald (Neu-Ulm - Bayern)": "097750000000", + "Oberroggenburger Wald (Neu-Ulm - Bayern)": "097750000000", + "Stoffenrieder Forst (Neu-Ulm - Bayern)": "097750000000", + "Unterroggenburger Wald (Neu-Ulm - Bayern)": "097750000000", + "Bodolz (Lindau (Bodensee) - Bayern)": "097760000000", + "Heimenkirch, M (Lindau (Bodensee) - Bayern)": "097760000000", + "Lindau (Bodensee), GKSt (Lindau (Bodensee) - Bayern)": "097760000000", + "Lindenberg i.Allgäu, St (Lindau (Bodensee) - Bayern)": "097760000000", + "Nonnenhorn (Lindau (Bodensee) - Bayern)": "097760000000", + "Opfenbach (Lindau (Bodensee) - Bayern)": "097760000000", + "Scheidegg, M (Lindau (Bodensee) - Bayern)": "097760000000", + "Wasserburg (Bodensee) (Lindau (Bodensee) - Bayern)": "097760000000", + "Weiler-Simmerberg, M (Lindau (Bodensee) - Bayern)": "097760000000", + "Hergatz (Lindau (Bodensee) - Bayern)": "097760000000", + "Hergensweiler (Lindau (Bodensee) - Bayern)": "097760000000", + "Sigmarszell (Lindau (Bodensee) - Bayern)": "097760000000", + "Weißensberg (Lindau (Bodensee) - Bayern)": "097760000000", + "Gestratz (Lindau (Bodensee) - Bayern)": "097760000000", + "Grünenbach (Lindau (Bodensee) - Bayern)": "097760000000", + "Maierhöfen (Lindau (Bodensee) - Bayern)": "097760000000", + "Röthenbach (Allgäu) (Lindau (Bodensee) - Bayern)": "097760000000", + "Oberreute (Lindau (Bodensee) - Bayern)": "097760000000", + "Stiefenhofen (Lindau (Bodensee) - Bayern)": "097760000000", + "Füssen, St (Ostallgäu - Bayern)": "097770000000", + "Germaringen (Ostallgäu - Bayern)": "097770000000", + "Lechbruck am See (Ostallgäu - Bayern)": "097770000000", + "Marktoberdorf, St (Ostallgäu - Bayern)": "097770000000", + "Mauerstetten (Ostallgäu - Bayern)": "097770000000", + "Nesselwang, M (Ostallgäu - Bayern)": "097770000000", + "Pfronten (Ostallgäu - Bayern)": "097770000000", + "Ronsberg, M (Ostallgäu - Bayern)": "097770000000", + "Schwangau (Ostallgäu - Bayern)": "097770000000", + "Halblech (Ostallgäu - Bayern)": "097770000000", + "Buchloe, St (Ostallgäu - Bayern)": "097770000000", + "Jengen (Ostallgäu - Bayern)": "097770000000", + "Lamerdingen (Ostallgäu - Bayern)": "097770000000", + "Waal, M (Ostallgäu - Bayern)": "097770000000", + "Irsee, M (Ostallgäu - Bayern)": "097770000000", + "Pforzen (Ostallgäu - Bayern)": "097770000000", + "Rieden (Ostallgäu - Bayern)": "097770000000", + "Kaltental, M (Ostallgäu - Bayern)": "097770000000", + "Oberostendorf (Ostallgäu - Bayern)": "097770000000", + "Osterzell (Ostallgäu - Bayern)": "097770000000", + "Stöttwang (Ostallgäu - Bayern)": "097770000000", + "Westendorf (Ostallgäu - Bayern)": "097770000000", + "Aitrang (Ostallgäu - Bayern)": "097770000000", + "Biessenhofen (Ostallgäu - Bayern)": "097770000000", + "Bidingen (Ostallgäu - Bayern)": "097770000000", + "Ruderatshofen (Ostallgäu - Bayern)": "097770000000", + "Baisweil (Ostallgäu - Bayern)": "097770000000", + "Eggenthal (Ostallgäu - Bayern)": "097770000000", + "Friesenried (Ostallgäu - Bayern)": "097770000000", + "Günzach (Ostallgäu - Bayern)": "097770000000", + "Obergünzburg, M (Ostallgäu - Bayern)": "097770000000", + "Untrasried (Ostallgäu - Bayern)": "097770000000", + "Görisried (Ostallgäu - Bayern)": "097770000000", + "Kraftisried (Ostallgäu - Bayern)": "097770000000", + "Unterthingau, M (Ostallgäu - Bayern)": "097770000000", + "Eisenberg (Ostallgäu - Bayern)": "097770000000", + "Hopferau (Ostallgäu - Bayern)": "097770000000", + "Lengenwang (Ostallgäu - Bayern)": "097770000000", + "Rückholz (Ostallgäu - Bayern)": "097770000000", + "Seeg (Ostallgäu - Bayern)": "097770000000", + "Wald (Ostallgäu - Bayern)": "097770000000", + "Rieden am Forggensee (Ostallgäu - Bayern)": "097770000000", + "Roßhaupten (Ostallgäu - Bayern)": "097770000000", + "Stötten a.Auerberg (Ostallgäu - Bayern)": "097770000000", + "Rettenbach a.Auerberg (Ostallgäu - Bayern)": "097770000000", + "Bad Wörishofen, St (Unterallgäu - Bayern)": "097780000000", + "Buxheim (Unterallgäu - Bayern)": "097780000000", + "Ettringen (Unterallgäu - Bayern)": "097780000000", + "Markt Rettenbach, M (Unterallgäu - Bayern)": "097780000000", + "Markt Wald, M (Unterallgäu - Bayern)": "097780000000", + "Mindelheim, St (Unterallgäu - Bayern)": "097780000000", + "Sontheim (Unterallgäu - Bayern)": "097780000000", + "Tussenhausen, M (Unterallgäu - Bayern)": "097780000000", + "Böhen (Unterallgäu - Bayern)": "097780000000", + "Hawangen (Unterallgäu - Bayern)": "097780000000", + "Ottobeuren, M (Unterallgäu - Bayern)": "097780000000", + "Babenhausen, M (Unterallgäu - Bayern)": "097780000000", + "Egg a.d.Günz (Unterallgäu - Bayern)": "097780000000", + "Kirchhaslach (Unterallgäu - Bayern)": "097780000000", + "Oberschönegg (Unterallgäu - Bayern)": "097780000000", + "Winterrieden (Unterallgäu - Bayern)": "097780000000", + "Kettershausen (Unterallgäu - Bayern)": "097780000000", + "Breitenbrunn (Unterallgäu - Bayern)": "097780000000", + "Oberrieden (Unterallgäu - Bayern)": "097780000000", + "Pfaffenhausen, M (Unterallgäu - Bayern)": "097780000000", + "Salgen (Unterallgäu - Bayern)": "097780000000", + "Eppishausen (Unterallgäu - Bayern)": "097780000000", + "Kirchheim i.Schw., M (Unterallgäu - Bayern)": "097780000000", + "Boos (Unterallgäu - Bayern)": "097780000000", + "Fellheim (Unterallgäu - Bayern)": "097780000000", + "Heimertingen (Unterallgäu - Bayern)": "097780000000", + "Niederrieden (Unterallgäu - Bayern)": "097780000000", + "Pleß (Unterallgäu - Bayern)": "097780000000", + "Erkheim, M (Unterallgäu - Bayern)": "097780000000", + "Lauben (Unterallgäu - Bayern)": "097780000000", + "Kammlach (Unterallgäu - Bayern)": "097780000000", + "Westerheim (Unterallgäu - Bayern)": "097780000000", + "Amberg (Unterallgäu - Bayern)": "097780000000", + "Türkheim, M (Unterallgäu - Bayern)": "097780000000", + "Rammingen (Unterallgäu - Bayern)": "097780000000", + "Wiedergeltingen (Unterallgäu - Bayern)": "097780000000", + "Benningen (Unterallgäu - Bayern)": "097780000000", + "Holzgünz (Unterallgäu - Bayern)": "097780000000", + "Lachen (Unterallgäu - Bayern)": "097780000000", + "Memmingerberg (Unterallgäu - Bayern)": "097780000000", + "Trunkelsberg (Unterallgäu - Bayern)": "097780000000", + "Ungerhausen (Unterallgäu - Bayern)": "097780000000", + "Apfeltrach (Unterallgäu - Bayern)": "097780000000", + "Dirlewang, M (Unterallgäu - Bayern)": "097780000000", + "Stetten (Unterallgäu - Bayern)": "097780000000", + "Unteregg (Unterallgäu - Bayern)": "097780000000", + "Kronburg (Unterallgäu - Bayern)": "097780000000", + "Lautrach (Unterallgäu - Bayern)": "097780000000", + "Legau, M (Unterallgäu - Bayern)": "097780000000", + "Bad Grönenbach, M (Unterallgäu - Bayern)": "097780000000", + "Wolfertschwenden (Unterallgäu - Bayern)": "097780000000", + "Woringen (Unterallgäu - Bayern)": "097780000000", + "Ungerhauser Wald (Unterallgäu - Bayern)": "097780000000", + "Asbach-Bäumenheim (Donau-Ries - Bayern)": "097790000000", + "Donauwörth, GKSt (Donau-Ries - Bayern)": "097790000000", + "Fremdingen (Donau-Ries - Bayern)": "097790000000", + "Harburg (Schwaben), St (Donau-Ries - Bayern)": "097790000000", + "Kaisheim, M (Donau-Ries - Bayern)": "097790000000", + "Marxheim (Donau-Ries - Bayern)": "097790000000", + "Mertingen (Donau-Ries - Bayern)": "097790000000", + "Möttingen (Donau-Ries - Bayern)": "097790000000", + "Nördlingen, GKSt (Donau-Ries - Bayern)": "097790000000", + "Oberndorf a.Lech (Donau-Ries - Bayern)": "097790000000", + "Tapfheim (Donau-Ries - Bayern)": "097790000000", + "Maihingen (Donau-Ries - Bayern)": "097790000000", + "Marktoffingen (Donau-Ries - Bayern)": "097790000000", + "Wallerstein, M (Donau-Ries - Bayern)": "097790000000", + "Auhausen (Donau-Ries - Bayern)": "097790000000", + "Ehingen a.Ries (Donau-Ries - Bayern)": "097790000000", + "Hainsfarth (Donau-Ries - Bayern)": "097790000000", + "Megesheim (Donau-Ries - Bayern)": "097790000000", + "Munningen (Donau-Ries - Bayern)": "097790000000", + "Oettingen i.Bay., St (Donau-Ries - Bayern)": "097790000000", + "Alerheim (Donau-Ries - Bayern)": "097790000000", + "Amerdingen (Donau-Ries - Bayern)": "097790000000", + "Deiningen (Donau-Ries - Bayern)": "097790000000", + "Ederheim (Donau-Ries - Bayern)": "097790000000", + "Forheim (Donau-Ries - Bayern)": "097790000000", + "Hohenaltheim (Donau-Ries - Bayern)": "097790000000", + "Mönchsdeggingen (Donau-Ries - Bayern)": "097790000000", + "Reimlingen (Donau-Ries - Bayern)": "097790000000", + "Wechingen (Donau-Ries - Bayern)": "097790000000", + "Fünfstetten (Donau-Ries - Bayern)": "097790000000", + "Huisheim (Donau-Ries - Bayern)": "097790000000", + "Otting (Donau-Ries - Bayern)": "097790000000", + "Wemding, St (Donau-Ries - Bayern)": "097790000000", + "Wolferstadt (Donau-Ries - Bayern)": "097790000000", + "Buchdorf (Donau-Ries - Bayern)": "097790000000", + "Daiting (Donau-Ries - Bayern)": "097790000000", + "Monheim, St (Donau-Ries - Bayern)": "097790000000", + "Rögling (Donau-Ries - Bayern)": "097790000000", + "Tagmersheim (Donau-Ries - Bayern)": "097790000000", + "Genderkingen (Donau-Ries - Bayern)": "097790000000", + "Holzheim (Donau-Ries - Bayern)": "097790000000", + "Münster (Donau-Ries - Bayern)": "097790000000", + "Niederschönenfeld (Donau-Ries - Bayern)": "097790000000", + "Rain, St (Donau-Ries - Bayern)": "097790000000", + "Dornstadt-Linkersbaindt (Donau-Ries - Bayern)": "097790000000", + "Esterholz (Donau-Ries - Bayern)": "097790000000", + "Altusried, M (Oberallgäu - Bayern)": "097800000000", + "Betzigau (Oberallgäu - Bayern)": "097800000000", + "Blaichach (Oberallgäu - Bayern)": "097800000000", + "Buchenberg, M (Oberallgäu - Bayern)": "097800000000", + "Burgberg i.Allgäu (Oberallgäu - Bayern)": "097800000000", + "Dietmannsried, M (Oberallgäu - Bayern)": "097800000000", + "Durach (Oberallgäu - Bayern)": "097800000000", + "Haldenwang (Oberallgäu - Bayern)": "097800000000", + "Bad Hindelang, M (Oberallgäu - Bayern)": "097800000000", + "Immenstadt i.Allgäu, St (Oberallgäu - Bayern)": "097800000000", + "Lauben (Oberallgäu - Bayern)": "097800000000", + "Oy-Mittelberg (Oberallgäu - Bayern)": "097800000000", + "Oberstaufen, M (Oberallgäu - Bayern)": "097800000000", + "Oberstdorf, M (Oberallgäu - Bayern)": "097800000000", + "Rettenberg (Oberallgäu - Bayern)": "097800000000", + "Sonthofen, St (Oberallgäu - Bayern)": "097800000000", + "Sulzberg, M (Oberallgäu - Bayern)": "097800000000", + "Waltenhofen (Oberallgäu - Bayern)": "097800000000", + "Wertach, M (Oberallgäu - Bayern)": "097800000000", + "Wiggensbach, M (Oberallgäu - Bayern)": "097800000000", + "Wildpoldsried (Oberallgäu - Bayern)": "097800000000", + "Balderschwang (Oberallgäu - Bayern)": "097800000000", + "Bolsterlang (Oberallgäu - Bayern)": "097800000000", + "Fischen i.Allgäu (Oberallgäu - Bayern)": "097800000000", + "Obermaiselstein (Oberallgäu - Bayern)": "097800000000", + "Ofterschwang (Oberallgäu - Bayern)": "097800000000", + "Missen-Wilhams (Oberallgäu - Bayern)": "097800000000", + "Weitnau, M (Oberallgäu - Bayern)": "097800000000", + "Kempter Wald (Oberallgäu - Bayern)": "097800000000", + "Saarbrücken, Landeshauptstadt (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Friedrichsthal, Stadt (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Großrosseln (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Heusweiler (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Kleinblittersdorf (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Püttlingen, Stadt (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Quierschied (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Riegelsberg (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Sulzbach/ Saar, Stadt (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Völklingen, Stadt (Saarbrücken, Regionalverband - Saarland)": "100410000000", + "Beckingen (Merzig-Wadern - Saarland)": "100420000000", + "Losheim am See (Merzig-Wadern - Saarland)": "100420000000", + "Merzig, Kreisstadt (Merzig-Wadern - Saarland)": "100420000000", + "Mettlach (Merzig-Wadern - Saarland)": "100420000000", + "Perl (Merzig-Wadern - Saarland)": "100420000000", + "Wadern, Stadt (Merzig-Wadern - Saarland)": "100420000000", + "Weiskirchen (Merzig-Wadern - Saarland)": "100420000000", + "Deutsch-luxemburgisches Hoheitsgebiet (Merzig-Wadern - Saarland)": "100420000000", + "Eppelborn (Neunkirchen - Saarland)": "100430000000", + "Illingen (Neunkirchen - Saarland)": "100430000000", + "Merchweiler (Neunkirchen - Saarland)": "100430000000", + "Neunkirchen, Kreisstadt (Neunkirchen - Saarland)": "100430000000", + "Ottweiler, Stadt (Neunkirchen - Saarland)": "100430000000", + "Schiffweiler (Neunkirchen - Saarland)": "100430000000", + "Spiesen-Elversberg (Neunkirchen - Saarland)": "100430000000", + "Dillingen/ Saar, Stadt (Saarlouis - Saarland)": "100440000000", + "Lebach, Stadt (Saarlouis - Saarland)": "100440000000", + "Nalbach (Saarlouis - Saarland)": "100440000000", + "Rehlingen-Siersburg (Saarlouis - Saarland)": "100440000000", + "Saarlouis, Kreisstadt (Saarlouis - Saarland)": "100440000000", + "Saarwellingen (Saarlouis - Saarland)": "100440000000", + "Schmelz (Saarlouis - Saarland)": "100440000000", + "Schwalbach (Saarlouis - Saarland)": "100440000000", + "Überherrn (Saarlouis - Saarland)": "100440000000", + "Wadgassen (Saarlouis - Saarland)": "100440000000", + "Wallerfangen (Saarlouis - Saarland)": "100440000000", + "Bous (Saarlouis - Saarland)": "100440000000", + "Ensdorf (Saarlouis - Saarland)": "100440000000", + "Bexbach, Stadt (Saarpfalz-Kreis - Saarland)": "100450000000", + "Blieskastel, Stadt (Saarpfalz-Kreis - Saarland)": "100450000000", + "Gersheim (Saarpfalz-Kreis - Saarland)": "100450000000", + "Homburg, Kreisstadt (Saarpfalz-Kreis - Saarland)": "100450000000", + "Kirkel (Saarpfalz-Kreis - Saarland)": "100450000000", + "Mandelbachtal (Saarpfalz-Kreis - Saarland)": "100450000000", + "St. Ingbert, Stadt (Saarpfalz-Kreis - Saarland)": "100450000000", + "Freisen (St. Wendel - Saarland)": "100460000000", + "Marpingen (St. Wendel - Saarland)": "100460000000", + "Namborn (St. Wendel - Saarland)": "100460000000", + "Nohfelden (St. Wendel - Saarland)": "100460000000", + "Nonnweiler (St. Wendel - Saarland)": "100460000000", + "Oberthal (St. Wendel - Saarland)": "100460000000", + "St. Wendel, Kreisstadt (St. Wendel - Saarland)": "100460000000", + "Tholey (St. Wendel - Saarland)": "100460000000", + "Berlin, Stadt": "110000000000", + "Brandenburg an der Havel, Stadt": "120510000000", + "Cottbus/Chóśebuz, Stadt": "120520000000", + "Frankfurt (Oder), Stadt": "120530000000", + "Potsdam, Stadt": "120540000000", + "Ahrensfelde (Barnim - Brandenburg)": "120600000000", + "Bernau bei Berlin, Stadt (Barnim - Brandenburg)": "120600000000", + "Eberswalde, Stadt (Barnim - Brandenburg)": "120600000000", + "Panketal (Barnim - Brandenburg)": "120600000000", + "Schorfheide (Barnim - Brandenburg)": "120600000000", + "Wandlitz (Barnim - Brandenburg)": "120600000000", + "Werneuchen, Stadt (Barnim - Brandenburg)": "120600000000", + "Biesenthal, Stadt (Barnim - Brandenburg)": "120600000000", + "Breydin (Barnim - Brandenburg)": "120600000000", + "Marienwerder (Barnim - Brandenburg)": "120600000000", + "Melchow (Barnim - Brandenburg)": "120600000000", + "Rüdnitz (Barnim - Brandenburg)": "120600000000", + "Sydower Fließ (Barnim - Brandenburg)": "120600000000", + "Althüttendorf (Barnim - Brandenburg)": "120600000000", + "Friedrichswalde (Barnim - Brandenburg)": "120600000000", + "Joachimsthal, Stadt (Barnim - Brandenburg)": "120600000000", + "Ziethen (Barnim - Brandenburg)": "120600000000", + "Britz (Barnim - Brandenburg)": "120600000000", + "Chorin (Barnim - Brandenburg)": "120600000000", + "Hohenfinow (Barnim - Brandenburg)": "120600000000", + "Liepe (Barnim - Brandenburg)": "120600000000", + "Lunow-Stolzenhagen (Barnim - Brandenburg)": "120600000000", + "Niederfinow (Barnim - Brandenburg)": "120600000000", + "Oderberg, Stadt (Barnim - Brandenburg)": "120600000000", + "Parsteinsee (Barnim - Brandenburg)": "120600000000", + "Bestensee (Dahme-Spreewald - Brandenburg)": "120610000000", + "Eichwalde (Dahme-Spreewald - Brandenburg)": "120610000000", + "Heidesee (Dahme-Spreewald - Brandenburg)": "120610000000", + "Heideblick (Dahme-Spreewald - Brandenburg)": "120610000000", + "Königs Wusterhausen, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Lübben (Spreewald) / Lubin (Błota), Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Luckau, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Märkische Heide/Markojska Góla (Dahme-Spreewald - Brandenburg)": "120610000000", + "Mittenwalde, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Schönefeld (Dahme-Spreewald - Brandenburg)": "120610000000", + "Schulzendorf (Dahme-Spreewald - Brandenburg)": "120610000000", + "Wildau, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Zeuthen (Dahme-Spreewald - Brandenburg)": "120610000000", + "Groß Köris (Dahme-Spreewald - Brandenburg)": "120610000000", + "Halbe (Dahme-Spreewald - Brandenburg)": "120610000000", + "Märkisch Buchholz, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Münchehofe (Dahme-Spreewald - Brandenburg)": "120610000000", + "Schwerin (Dahme-Spreewald - Brandenburg)": "120610000000", + "Teupitz, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Alt Zauche-Wußwerk/Stara Niwa-Wózwjerch (Dahme-Spreewald - Brandenburg)": "120610000000", + "Byhleguhre-Byhlen/Beła Góra-Bělin (Dahme-Spreewald - Brandenburg)": "120610000000", + "Jamlitz (Dahme-Spreewald - Brandenburg)": "120610000000", + "Lieberose, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Neu Zauche/Nowa Niwa (Dahme-Spreewald - Brandenburg)": "120610000000", + "Schwielochsee/Gójacki Jazor (Dahme-Spreewald - Brandenburg)": "120610000000", + "Spreewaldheide/Błośańska Góla (Dahme-Spreewald - Brandenburg)": "120610000000", + "Straupitz (Spreewald)/Tšupc (Błota) (Dahme-Spreewald - Brandenburg)": "120610000000", + "Bersteland (Dahme-Spreewald - Brandenburg)": "120610000000", + "Drahnsdorf (Dahme-Spreewald - Brandenburg)": "120610000000", + "Golßen, Stadt (Dahme-Spreewald - Brandenburg)": "120610000000", + "Kasel-Golzig (Dahme-Spreewald - Brandenburg)": "120610000000", + "Krausnick-Groß Wasserburg (Dahme-Spreewald - Brandenburg)": "120610000000", + "Rietzneuendorf-Staakow (Dahme-Spreewald - Brandenburg)": "120610000000", + "Schlepzig/Słopišća (Dahme-Spreewald - Brandenburg)": "120610000000", + "Schönwald (Dahme-Spreewald - Brandenburg)": "120610000000", + "Steinreich (Dahme-Spreewald - Brandenburg)": "120610000000", + "Unterspreewald (Dahme-Spreewald - Brandenburg)": "120610000000", + "Doberlug-Kirchhain, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Elsterwerda, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Finsterwalde, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Herzberg (Elster), Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Röderland (Elbe-Elster - Brandenburg)": "120620000000", + "Schönewalde, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Sonnewalde, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Bad Liebenwerda, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Falkenberg/Elster, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Mühlberg/Elbe, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Uebigau-Wahrenbrück, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Heideland (Elbe-Elster - Brandenburg)": "120620000000", + "Rückersdorf (Elbe-Elster - Brandenburg)": "120620000000", + "Schilda (Elbe-Elster - Brandenburg)": "120620000000", + "Schönborn (Elbe-Elster - Brandenburg)": "120620000000", + "Tröbitz (Elbe-Elster - Brandenburg)": "120620000000", + "Crinitz (Elbe-Elster - Brandenburg)": "120620000000", + "Lichterfeld-Schacksdorf (Elbe-Elster - Brandenburg)": "120620000000", + "Massen-Niederlausitz (Elbe-Elster - Brandenburg)": "120620000000", + "Sallgast (Elbe-Elster - Brandenburg)": "120620000000", + "Gorden-Staupitz (Elbe-Elster - Brandenburg)": "120620000000", + "Hohenleipisch (Elbe-Elster - Brandenburg)": "120620000000", + "Plessa (Elbe-Elster - Brandenburg)": "120620000000", + "Schraden (Elbe-Elster - Brandenburg)": "120620000000", + "Fichtwald (Elbe-Elster - Brandenburg)": "120620000000", + "Hohenbucko (Elbe-Elster - Brandenburg)": "120620000000", + "Kremitzaue (Elbe-Elster - Brandenburg)": "120620000000", + "Lebusa (Elbe-Elster - Brandenburg)": "120620000000", + "Schlieben, Stadt (Elbe-Elster - Brandenburg)": "120620000000", + "Gröden (Elbe-Elster - Brandenburg)": "120620000000", + "Großthiemig (Elbe-Elster - Brandenburg)": "120620000000", + "Hirschfeld (Elbe-Elster - Brandenburg)": "120620000000", + "Merzdorf (Elbe-Elster - Brandenburg)": "120620000000", + "Brieselang (Havelland - Brandenburg)": "120630000000", + "Dallgow-Döberitz (Havelland - Brandenburg)": "120630000000", + "Falkensee, Stadt (Havelland - Brandenburg)": "120630000000", + "Ketzin/Havel, Stadt (Havelland - Brandenburg)": "120630000000", + "Milower Land (Havelland - Brandenburg)": "120630000000", + "Nauen, Stadt (Havelland - Brandenburg)": "120630000000", + "Premnitz, Stadt (Havelland - Brandenburg)": "120630000000", + "Rathenow, Stadt (Havelland - Brandenburg)": "120630000000", + "Schönwalde-Glien (Havelland - Brandenburg)": "120630000000", + "Wustermark (Havelland - Brandenburg)": "120630000000", + "Friesack, Stadt (Havelland - Brandenburg)": "120630000000", + "Wiesenaue (Havelland - Brandenburg)": "120630000000", + "Mühlenberge (Havelland - Brandenburg)": "120630000000", + "Paulinenaue (Havelland - Brandenburg)": "120630000000", + "Pessin (Havelland - Brandenburg)": "120630000000", + "Retzow (Havelland - Brandenburg)": "120630000000", + "Kotzen (Havelland - Brandenburg)": "120630000000", + "Märkisch Luch (Havelland - Brandenburg)": "120630000000", + "Nennhausen (Havelland - Brandenburg)": "120630000000", + "Stechow-Ferchesar (Havelland - Brandenburg)": "120630000000", + "Gollenberg (Havelland - Brandenburg)": "120630000000", + "Großderschau (Havelland - Brandenburg)": "120630000000", + "Havelaue (Havelland - Brandenburg)": "120630000000", + "Kleßen-Görne (Havelland - Brandenburg)": "120630000000", + "Rhinow, Stadt (Havelland - Brandenburg)": "120630000000", + "Seeblick (Havelland - Brandenburg)": "120630000000", + "Altlandsberg, Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Bad Freienwalde (Oder), Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Fredersdorf-Vogelsdorf (Märkisch-Oderland - Brandenburg)": "120640000000", + "Hoppegarten (Märkisch-Oderland - Brandenburg)": "120640000000", + "Letschin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Müncheberg, Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Neuenhagen bei Berlin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Petershagen/Eggersdorf (Märkisch-Oderland - Brandenburg)": "120640000000", + "Rüdersdorf bei Berlin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Seelow, Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Strausberg, Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Wriezen, Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Beiersdorf-Freudenberg (Märkisch-Oderland - Brandenburg)": "120640000000", + "Falkenberg (Märkisch-Oderland - Brandenburg)": "120640000000", + "Heckelberg-Brunow (Märkisch-Oderland - Brandenburg)": "120640000000", + "Höhenland (Märkisch-Oderland - Brandenburg)": "120640000000", + "Alt Tucheband (Märkisch-Oderland - Brandenburg)": "120640000000", + "Bleyen-Genschmar (Märkisch-Oderland - Brandenburg)": "120640000000", + "Golzow (Märkisch-Oderland - Brandenburg)": "120640000000", + "Küstriner Vorland (Märkisch-Oderland - Brandenburg)": "120640000000", + "Zechin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Lebus, Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Podelzig (Märkisch-Oderland - Brandenburg)": "120640000000", + "Reitwein (Märkisch-Oderland - Brandenburg)": "120640000000", + "Treplin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Zeschdorf (Märkisch-Oderland - Brandenburg)": "120640000000", + "Buckow (Märkische Schweiz), Stadt (Märkisch-Oderland - Brandenburg)": "120640000000", + "Garzau-Garzin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Oberbarnim (Märkisch-Oderland - Brandenburg)": "120640000000", + "Rehfelde (Märkisch-Oderland - Brandenburg)": "120640000000", + "Waldsieversdorf (Märkisch-Oderland - Brandenburg)": "120640000000", + "Gusow-Platkow (Märkisch-Oderland - Brandenburg)": "120640000000", + "Märkische Höhe (Märkisch-Oderland - Brandenburg)": "120640000000", + "Neuhardenberg (Märkisch-Oderland - Brandenburg)": "120640000000", + "Falkenhagen (Mark) (Märkisch-Oderland - Brandenburg)": "120640000000", + "Fichtenhöhe (Märkisch-Oderland - Brandenburg)": "120640000000", + "Lietzen (Märkisch-Oderland - Brandenburg)": "120640000000", + "Lindendorf (Märkisch-Oderland - Brandenburg)": "120640000000", + "Vierlinden (Märkisch-Oderland - Brandenburg)": "120640000000", + "Bliesdorf (Märkisch-Oderland - Brandenburg)": "120640000000", + "Neulewin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Neutrebbin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Oderaue (Märkisch-Oderland - Brandenburg)": "120640000000", + "Prötzel (Märkisch-Oderland - Brandenburg)": "120640000000", + "Reichenow-Möglin (Märkisch-Oderland - Brandenburg)": "120640000000", + "Birkenwerder (Oberhavel - Brandenburg)": "120650000000", + "Fürstenberg/Havel, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Glienicke/Nordbahn (Oberhavel - Brandenburg)": "120650000000", + "Hennigsdorf, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Hohen Neuendorf, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Kremmen, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Leegebruch (Oberhavel - Brandenburg)": "120650000000", + "Liebenwalde, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Löwenberger Land (Oberhavel - Brandenburg)": "120650000000", + "Mühlenbecker Land (Oberhavel - Brandenburg)": "120650000000", + "Oberkrämer (Oberhavel - Brandenburg)": "120650000000", + "Oranienburg, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Velten, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Zehdenick, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Gransee, Stadt (Oberhavel - Brandenburg)": "120650000000", + "Großwoltersdorf (Oberhavel - Brandenburg)": "120650000000", + "Schönermark (Oberhavel - Brandenburg)": "120650000000", + "Sonnenberg (Oberhavel - Brandenburg)": "120650000000", + "Stechlin (Oberhavel - Brandenburg)": "120650000000", + "Calau/Kalawa, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Großräschen/Rań, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Lauchhammer, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Lübbenau/Spreewald / Lubnjow/Błota, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Schipkau (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Schwarzheide, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Senftenberg/Zły Komorow, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Vetschau/Spreewald / Wětošow/Błota, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Altdöbern (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Bronkow (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Luckaitztal (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Neu-Seeland/Nowa Jazorina (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Neupetershain/Nowe Wiki (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Frauendorf (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Großkmehlen (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Kroppen (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Lindenau (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Ortrand, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Tettau (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Grünewald (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Guteborn (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Hermsdorf (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Hohenbocka (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Ruhland, Stadt (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Schwarzbach (Oberspreewald-Lausitz - Brandenburg)": "120660000000", + "Beeskow, Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Eisenhüttenstadt, Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Erkner, Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Friedland, Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Fürstenwalde/Spree, Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Grünheide (Mark) (Oder-Spree - Brandenburg)": "120670000000", + "Rietz-Neuendorf (Oder-Spree - Brandenburg)": "120670000000", + "Schöneiche bei Berlin (Oder-Spree - Brandenburg)": "120670000000", + "Storkow (Mark), Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Tauche (Oder-Spree - Brandenburg)": "120670000000", + "Woltersdorf (Oder-Spree - Brandenburg)": "120670000000", + "Brieskow-Finkenheerd (Oder-Spree - Brandenburg)": "120670000000", + "Groß Lindow (Oder-Spree - Brandenburg)": "120670000000", + "Vogelsang (Oder-Spree - Brandenburg)": "120670000000", + "Wiesenau (Oder-Spree - Brandenburg)": "120670000000", + "Ziltendorf (Oder-Spree - Brandenburg)": "120670000000", + "Lawitz (Oder-Spree - Brandenburg)": "120670000000", + "Neißemünde (Oder-Spree - Brandenburg)": "120670000000", + "Neuzelle (Oder-Spree - Brandenburg)": "120670000000", + "Berkenbrück (Oder-Spree - Brandenburg)": "120670000000", + "Briesen (Mark) (Oder-Spree - Brandenburg)": "120670000000", + "Jacobsdorf (Oder-Spree - Brandenburg)": "120670000000", + "Steinhöfel (Oder-Spree - Brandenburg)": "120670000000", + "Bad Saarow (Oder-Spree - Brandenburg)": "120670000000", + "Diensdorf-Radlow (Oder-Spree - Brandenburg)": "120670000000", + "Langewahl (Oder-Spree - Brandenburg)": "120670000000", + "Reichenwalde (Oder-Spree - Brandenburg)": "120670000000", + "Wendisch Rietz (Oder-Spree - Brandenburg)": "120670000000", + "Grunow-Dammendorf (Oder-Spree - Brandenburg)": "120670000000", + "Mixdorf (Oder-Spree - Brandenburg)": "120670000000", + "Müllrose, Stadt (Oder-Spree - Brandenburg)": "120670000000", + "Ragow-Merz (Oder-Spree - Brandenburg)": "120670000000", + "Schlaubetal (Oder-Spree - Brandenburg)": "120670000000", + "Siehdichum (Oder-Spree - Brandenburg)": "120670000000", + "Gosen-Neu Zittau (Oder-Spree - Brandenburg)": "120670000000", + "Rauen (Oder-Spree - Brandenburg)": "120670000000", + "Spreenhagen (Oder-Spree - Brandenburg)": "120670000000", + "Fehrbellin (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Heiligengrabe (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Kyritz, Stadt (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Neuruppin, Stadt (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Rheinsberg, Stadt (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Wittstock/Dosse, Stadt (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Wusterhausen/Dosse (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Herzberg (Mark) (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Lindow (Mark), Stadt (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Rüthnick (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Vielitzsee (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Breddin (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Dreetz (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Neustadt (Dosse), Stadt (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Sieversdorf-Hohenofen (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Stüdenitz-Schönermark (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Zernitz-Lohm (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Dabergotz (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Märkisch Linden (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Storbeck-Frankendorf (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Temnitzquell (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Temnitztal (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Walsleben (Ostprignitz-Ruppin - Brandenburg)": "120680000000", + "Beelitz, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Bad Belzig, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Groß Kreutz (Havel) (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Kleinmachnow (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Kloster Lehnin (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Michendorf (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Nuthetal (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Schwielowsee (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Seddiner See (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Stahnsdorf (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Teltow, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Treuenbrietzen, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Werder (Havel), Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Wiesenburg/Mark (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Beetzsee (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Beetzseeheide (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Havelsee, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Päwesin (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Roskow (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Borkheide (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Borkwalde (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Brück, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Golzow (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Linthe (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Planebruch (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Mühlenfließ (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Niemegk, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Planetal (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Rabenstein/Fläming (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Bensdorf (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Rosenau (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Wusterwitz (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Buckautal (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Görzke (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Gräben (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Wenzlow (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Wollin (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Ziesar, Stadt (Potsdam-Mittelmark - Brandenburg)": "120690000000", + "Groß Pankow (Prignitz) (Prignitz - Brandenburg)": "120700000000", + "Gumtow (Prignitz - Brandenburg)": "120700000000", + "Karstädt (Prignitz - Brandenburg)": "120700000000", + "Perleberg, Stadt (Prignitz - Brandenburg)": "120700000000", + "Plattenburg (Prignitz - Brandenburg)": "120700000000", + "Pritzwalk, Stadt (Prignitz - Brandenburg)": "120700000000", + "Wittenberge, Stadt (Prignitz - Brandenburg)": "120700000000", + "Bad Wilsnack, Stadt (Prignitz - Brandenburg)": "120700000000", + "Breese (Prignitz - Brandenburg)": "120700000000", + "Legde/Quitzöbel (Prignitz - Brandenburg)": "120700000000", + "Rühstädt (Prignitz - Brandenburg)": "120700000000", + "Weisen (Prignitz - Brandenburg)": "120700000000", + "Cumlosen (Prignitz - Brandenburg)": "120700000000", + "Lanz (Prignitz - Brandenburg)": "120700000000", + "Lenzen (Elbe), Stadt (Prignitz - Brandenburg)": "120700000000", + "Lenzerwische (Prignitz - Brandenburg)": "120700000000", + "Gerdshagen (Prignitz - Brandenburg)": "120700000000", + "Halenbeck-Rohlsdorf (Prignitz - Brandenburg)": "120700000000", + "Kümmernitztal (Prignitz - Brandenburg)": "120700000000", + "Marienfließ (Prignitz - Brandenburg)": "120700000000", + "Meyenburg, Stadt (Prignitz - Brandenburg)": "120700000000", + "Berge (Prignitz - Brandenburg)": "120700000000", + "Gülitz-Reetz (Prignitz - Brandenburg)": "120700000000", + "Pirow (Prignitz - Brandenburg)": "120700000000", + "Putlitz, Stadt (Prignitz - Brandenburg)": "120700000000", + "Triglitz (Prignitz - Brandenburg)": "120700000000", + "Drebkau/Drjowk, Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Forst (Lausitz)/Baršć (Łužyca), Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Guben, Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Kolkwitz/Gołkojce (Spree-Neiße - Brandenburg)": "120710000000", + "Neuhausen/Spree / Kopańce/Sprjewja (Spree-Neiße - Brandenburg)": "120710000000", + "Schenkendöbern/Derbno (Spree-Neiße - Brandenburg)": "120710000000", + "Spremberg/Grodk, Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Welzow/Wjelcej, Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Briesen/Brjazyna (Spree-Neiße - Brandenburg)": "120710000000", + "Burg (Spreewald)/Bórkowy (Błota) (Spree-Neiße - Brandenburg)": "120710000000", + "Dissen-Striesow/Dešno-Strjažow (Spree-Neiße - Brandenburg)": "120710000000", + "Guhrow/Góry (Spree-Neiße - Brandenburg)": "120710000000", + "Schmogrow-Fehrow/Smogorjow-Prjawoz (Spree-Neiße - Brandenburg)": "120710000000", + "Werben/Wjerbno (Spree-Neiße - Brandenburg)": "120710000000", + "Döbern/Derbno, Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Felixsee/Feliksowy Jazor (Spree-Neiße - Brandenburg)": "120710000000", + "Groß Schacksdorf-Simmersdorf (Spree-Neiße - Brandenburg)": "120710000000", + "Jämlitz-Klein Düben (Spree-Neiße - Brandenburg)": "120710000000", + "Neiße-Malxetal/Dolina Nysa-Małksa (Spree-Neiße - Brandenburg)": "120710000000", + "Tschernitz/Cersk (Spree-Neiße - Brandenburg)": "120710000000", + "Wiesengrund/Łukojce (Spree-Neiße - Brandenburg)": "120710000000", + "Drachhausen/Hochoza (Spree-Neiße - Brandenburg)": "120710000000", + "Drehnow/Drjenow (Spree-Neiße - Brandenburg)": "120710000000", + "Heinersbrück/Móst (Spree-Neiße - Brandenburg)": "120710000000", + "Jänschwalde/Janšojce (Spree-Neiße - Brandenburg)": "120710000000", + "Peitz/Picnjo, Stadt (Spree-Neiße - Brandenburg)": "120710000000", + "Tauer/Turjej (Spree-Neiße - Brandenburg)": "120710000000", + "Teichland/Gatojce (Spree-Neiße - Brandenburg)": "120710000000", + "Turnow-Preilack/Turnow-Pśiłuk (Spree-Neiße - Brandenburg)": "120710000000", + "Am Mellensee (Teltow-Fläming - Brandenburg)": "120720000000", + "Baruth/Mark, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Blankenfelde-Mahlow (Teltow-Fläming - Brandenburg)": "120720000000", + "Großbeeren (Teltow-Fläming - Brandenburg)": "120720000000", + "Jüterbog, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Luckenwalde, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Ludwigsfelde, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Niedergörsdorf (Teltow-Fläming - Brandenburg)": "120720000000", + "Nuthe-Urstromtal (Teltow-Fläming - Brandenburg)": "120720000000", + "Rangsdorf (Teltow-Fläming - Brandenburg)": "120720000000", + "Trebbin, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Zossen, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Dahme/Mark, Stadt (Teltow-Fläming - Brandenburg)": "120720000000", + "Dahmetal (Teltow-Fläming - Brandenburg)": "120720000000", + "Ihlow (Teltow-Fläming - Brandenburg)": "120720000000", + "Niederer Fläming (Teltow-Fläming - Brandenburg)": "120720000000", + "Angermünde, Stadt (Uckermark - Brandenburg)": "120730000000", + "Boitzenburger Land (Uckermark - Brandenburg)": "120730000000", + "Lychen, Stadt (Uckermark - Brandenburg)": "120730000000", + "Nordwestuckermark (Uckermark - Brandenburg)": "120730000000", + "Prenzlau, Stadt (Uckermark - Brandenburg)": "120730000000", + "Schwedt/Oder, Stadt (Uckermark - Brandenburg)": "120730000000", + "Templin, Stadt (Uckermark - Brandenburg)": "120730000000", + "Uckerland (Uckermark - Brandenburg)": "120730000000", + "Brüssow, Stadt (Uckermark - Brandenburg)": "120730000000", + "Carmzow-Wallmow (Uckermark - Brandenburg)": "120730000000", + "Göritz (Uckermark - Brandenburg)": "120730000000", + "Schenkenberg (Uckermark - Brandenburg)": "120730000000", + "Schönfeld (Uckermark - Brandenburg)": "120730000000", + "Casekow (Uckermark - Brandenburg)": "120730000000", + "Gartz (Oder), Stadt (Uckermark - Brandenburg)": "120730000000", + "Hohenselchow-Groß Pinnow (Uckermark - Brandenburg)": "120730000000", + "Mescherin (Uckermark - Brandenburg)": "120730000000", + "Tantow (Uckermark - Brandenburg)": "120730000000", + "Flieth-Stegelitz (Uckermark - Brandenburg)": "120730000000", + "Gerswalde (Uckermark - Brandenburg)": "120730000000", + "Milmersdorf (Uckermark - Brandenburg)": "120730000000", + "Mittenwalde (Uckermark - Brandenburg)": "120730000000", + "Temmen-Ringenwalde (Uckermark - Brandenburg)": "120730000000", + "Gramzow (Uckermark - Brandenburg)": "120730000000", + "Grünow (Uckermark - Brandenburg)": "120730000000", + "Oberuckersee (Uckermark - Brandenburg)": "120730000000", + "Randowtal (Uckermark - Brandenburg)": "120730000000", + "Uckerfelde (Uckermark - Brandenburg)": "120730000000", + "Zichow (Uckermark - Brandenburg)": "120730000000", + "Berkholz-Meyenburg (Uckermark - Brandenburg)": "120730000000", + "Mark Landin (Uckermark - Brandenburg)": "120730000000", + "Pinnow (Uckermark - Brandenburg)": "120730000000", + "Passow (Uckermark - Brandenburg)": "120730000000", + "Küstengewässer einschl. Anteil am Festlandsockel": "130000000000", + "Rostock, Hanse- und Universitätsstadt": "130030000000", + "Schwerin, Landeshauptstadt": "130040000000", + "Dargun, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Demmin, Hansestadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Feldberger Seenlandschaft (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neubrandenburg, Vier-Tore-Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neustrelitz, Residenzstadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Waren (Müritz), Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Beggerow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Borrentin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Hohenbollentin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Hohenmocker (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kentzlin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kletzin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Lindenberg (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Meesiger (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Nossendorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Sarow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Schönfeld (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Siedenbrünzow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Sommersdorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Utzedel (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Verchen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Warrenzin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Datzetal (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Friedland, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Galenbeck (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Basedow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Faulenrost (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Gielow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kummerow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Malchin, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neukalen, Peenestadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Alt Schwerin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Fünfseen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Göhren-Lebbin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Malchow, Inselstadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Nossentiner Hütte (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Penkow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Silz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Walow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Zislow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Mirow, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Priepert (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Wesenberg, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Wustrow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Blankensee (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Blumenholz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Carpin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Godendorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Grünow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Hohenzieritz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Klein Vielen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kratzeburg (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Möllenbeck (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Userin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Wokuhl-Dabelow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Beseritz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Blankenhof (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Brunn (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neddemin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neuenkirchen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neverin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Sponholz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Staven (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Trollenhagen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Woggersin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Wulkenzin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Zirzow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Ankershagen, Schliemanngemeinde (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Möllenhagen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Penzlin, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kuckssee (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Altenhof (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Bollewick (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Buchholz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Bütow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Fincken (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Gotthun (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Groß Kelle (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kieve (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Lärz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Leizen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Melz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Priborn (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Rechlin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Röbel/Müritz, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Schwarz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Sietow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Stuer (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Eldetal (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Südmüritz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Grabowhöfe (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Groß Plasten (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Hohen Wangelin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Jabel (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kargow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Klink (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Klocksin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Moltzow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Torgelow am See (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Vollrathsruhe (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Peenehagen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Schloen-Dratow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Burg Stargard, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Cölpin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Groß Nemerow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Holldorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Lindetal (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Pragsdorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Bredenfelde (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Briggow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Grammentin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Gülzow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Ivenack (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Jürgenstorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kittendorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Knorrendorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Mölln (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Ritzerow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Rosenow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Stavenhagen, Reuterstadt, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Zettemin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Altenhagen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Altentreptow, Stadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Bartow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Breesen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Breest (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Burow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Gnevkow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Golchen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Grapzow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Grischow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Groß Teetzleben (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Gültz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kriesow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Pripsleben (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Röckwitz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Siedenbollentin (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Tützpatz (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Werder (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Wildberg (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Wolde (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Groß Miltzow (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Kublank (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Neetzka (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Schönbeck (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Schönhausen (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Voigtsdorf (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Woldegk, Windmühlenstadt (Mecklenburgische Seenplatte - Mecklenburg-Vorpommern)": "130710000000", + "Bad Doberan, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Dummerstorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Graal-Müritz, Ostseeheilbad (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Güstrow, Barlachstadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Kröpelin, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Kühlungsborn, Ostseebad, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Neubukow, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Sanitz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Satow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Teterow, Bergringstadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Admannshagen-Bargeshagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Bartenshagen-Parkentin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Börgerende-Rethwisch (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Hohenfelde (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Nienhagen, Ostseebad (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Reddelich (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Retschow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Steffenshagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Wittenbeck (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Baumgarten (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Bernitt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Bützow, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Dreetz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Jürgenshagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Klein Belitz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Penzin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Rühn (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Steinhagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Tarnow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Warnow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Zepelin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Broderstorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Poppendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Roggentin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Thulendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Altkalen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Behren-Lübchin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Finkenthal (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Gnoien, Warbelstadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Walkendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Glasewitz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Groß Schwiesow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Gülzow-Prüzen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Gutow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Klein Upahl (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Kuhs (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Lohmen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Lüssow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Mistorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Mühl Rosin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Plaaz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Reimershagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Sarmstorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Zehna (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Dobbin-Linstow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Hoppenrade (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Krakow am See, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Kuchelmiß (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Lalendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Dolgen am See (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Hohen Sprenz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Laage, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Wardow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Alt Sührkow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Dahmen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Dalkendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Groß Roge (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Groß Wokern (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Groß Wüstenfelde (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Hohen Demzin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Jördenstorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Lelkendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Prebberede (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Schorssow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Schwasdorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Sukow-Levitzow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Thürkow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Warnkenhagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Alt Bukow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Am Salzhaff (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Bastorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Biendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Carinerland (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Rerik, Ostseebad, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Bentwisch (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Blankenhagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Gelbensande (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Mönchhagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Rövershagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Benitz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Bröbberow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Kassow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Rukieten (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Schwaan, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Vorbeck (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Wiendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Cammin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Gnewitz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Grammow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Nustrow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Selpin (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Stubbendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Tessin, Stadt (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Thelkow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Zarnewanz (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Elmenhorst/Lichtenhagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Kritzmow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Lambrechtshagen (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Papendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Pölchow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Stäbelow (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Ziesendorf (Rostock - Mecklenburg-Vorpommern)": "130720000000", + "Binz, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Grimmen, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Marlow, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Putbus, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Sassnitz, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Stralsund, Hansestadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Süderholz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Zingst, Ostseeheilbad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Altenpleen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Groß Mohrdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Klausdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Kramerhof (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Preetz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Prohn (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Barth, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Divitz-Spoldershagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Fuhlendorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Karnin (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Kenz-Küstrow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Löbnitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Lüdershagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Pruchten (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Saal (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Trinwillershagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Bergen auf Rügen, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Buschvitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Garz/Rügen, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Gustow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Lietzow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Parchtitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Patzig (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Poseritz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Ralswiek (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Rappin (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Sehlen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Ahrenshoop, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Born a. Darß (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Dierhagen, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Prerow, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Wieck a. Darß (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Wustrow, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Franzburg, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Glewitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Gremersdorf-Buchholz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Millienhagen-Oebelitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Papenhagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Richtenberg, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Splietsdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Velgast (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Weitenhagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Wendisch Baggendorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Elmenhorst (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Sundhagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Wittenhagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Baabe, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Göhren, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Lancken-Granitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Sellin, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Zirkow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Mönchgut, Ostseebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Groß Kordshagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Jakobsdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Lüssow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Niepars (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Pantelitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Steinhagen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Wendorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Zarrendorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Altenkirchen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Breege (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Dranske (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Glowe (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Lohme (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Putgarten (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Sagard (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Wiek (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Bad Sülze, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Dettmannsdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Deyelsdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Drechow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Eixen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Grammendorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Gransebieth (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Hugoldsdorf (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Lindholz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Tribsees, Stadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Ahrenshagen-Daskow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Ribnitz-Damgarten, Bernsteinstadt (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Schlemmin (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Semlow (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Altefähr (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Dreschvitz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Gingst (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Insel Hiddensee, Seebad (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Kluis (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Neuenkirchen (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Rambin (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Samtens (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Schaprode (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Trent (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Ummanz (Vorpommern-Rügen - Mecklenburg-Vorpommern)": "130730000000", + "Grevesmühlen, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Insel Poel, Ostseebad (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Wismar, Hansestadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Bad Kleinen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Barnekow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Bobitz (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Dorf Mecklenburg (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Groß Stieten (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Hohen Viecheln (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Lübow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Metelsdorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Ventschow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Dragun (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Gadebusch, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Kneese (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Krembz (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Mühlen Eichsen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Roggendorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Rögnitz (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Veelböken (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Bernstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Gägelow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Roggenstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Rüting (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Testorf-Steinfort (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Upahl (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Warnow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Stepenitztal (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Boltenhagen, Ostseebad (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Damshagen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Hohenkirchen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Kalkhorst (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Klütz, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Zierow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Alt Meteln (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Brüsewitz (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Cramonshagen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Dalberg-Wendelstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Gottesgabe (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Grambow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Klein Trebbow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Lübstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Lützow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Perlin (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Pingelshagen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Pokrent (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Schildetal (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Seehof (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Zickhusen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Benz (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Blowatz (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Boiensdorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Hornstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Krusenhagen (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Neuburg (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Bibow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Glasin (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Jesendorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Lübberstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Neukloster, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Passee (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Warin, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Zurow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Züsow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Carlow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Dechow (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Groß Molzahn (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Holdorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Königsfeld (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Rehna, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Rieps (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Schlagsdorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Thandorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Utecht (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Wedendorfersee (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Dassow, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Grieben (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Lüdersdorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Menzendorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Roduchelstorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Schönberg, Stadt (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Selmsdorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Siemz-Niendorf (Nordwestmecklenburg - Mecklenburg-Vorpommern)": "130740000000", + "Anklam, Hansestadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Greifswald, Universitäts- und Hansestadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Heringsdorf, Ostseebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Pasewalk, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Strasburg (Uckermark), Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ueckermünde, Seebad , Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Buggenhagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Krummin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Lassan, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Lütow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Sauzin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Wolgast, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Zemitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ahlbeck (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Altwarp (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Eggesin, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Grambin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Hintersee (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Leopoldshagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Liepgarten (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Lübs (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Luckow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Meiersberg (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Mönkebude (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Vogelsang-Warsin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Bargischow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Blesewitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Boldekow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Bugewitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Butzow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ducherow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Iven (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Krien (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Krusenfelde (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Medow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Neu Kosenow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Neuenkirchen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Postlow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rossin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Sarnow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Spantekow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Stolpe an der Peene (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Neetzow-Liepen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Alt Tellin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Bentzin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Daberkow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Jarmen, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Kruckow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Tutow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Völschow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Behrenhoff (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Dargelin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Dersekow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Hinrichshagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Levenhagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Mesekenhagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Wackerow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Weitenhagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Bergholz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Blankensee (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Boock (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Glasow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Grambow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Krackow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Löcknitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Nadrensee (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Penkun, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Plöwen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ramin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rossow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rothenklempenow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Brünzow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Hanshagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Katzow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Kemnitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Kröslin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Loissin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Lubmin, Seebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Neu Boltenhagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rubenow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Wusterhusen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Görmin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Loitz, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Sassen-Trantow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Altwigshagen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ferdinandshof (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Hammer a.d. Uecker (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Heinrichswalde (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rothemühl (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Torgelow, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Wilhelmsburg (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Brietzig (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Fahrenwalde (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Groß Luckow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Jatznick (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Koblentz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Krugsdorf (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Nieden (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Papendorf (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Polzow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rollwitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Schönwalde (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Viereck (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Zerrenthin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Karlshagen, Ostseebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Mölschow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Peenemünde (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Trassenheide, Ostseebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Zinnowitz, Ostseebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Benz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Dargen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Garz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Kamminke (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Korswandt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Koserow, Ostseebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Loddin, Seebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Mellenthin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Pudagla (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rankwitz (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Stolpe auf Usedom (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ückeritz, Seebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Usedom, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Zempin, Seebad (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Zirchow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Bandelin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Gribow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Groß Kiesow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Groß Polzin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Gützkow, Stadt (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Klein Bünzow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Murchin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Rubkow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Schmatzin (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Wrangelsburg (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Ziethen (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Züssow (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Karlsburg (Vorpommern-Greifswald - Mecklenburg-Vorpommern)": "130750000000", + "Boizenburg/ Elbe, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Hagenow, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Lübtheen, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Ludwigslust, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Parchim, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Bengerstorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Besitz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Brahlstorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dersenow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gresse (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Greven (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Neu Gülze (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Nostorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Schwanheide (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Teldau (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Tessin b. Boizenburg (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dömitz, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Grebs-Niendorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Karenz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Malk Göhren (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Malliß (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Neu Kaliß (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Vielank (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gallin-Kuppentin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Granzin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kreien (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kritzow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Lübz, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Passow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Siggelkow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Werder (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gehlsbach (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Ruhner Berge (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dobbertin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Goldberg, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Mestlin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Neu Poserin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Techentin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Balow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Brunow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dambeck (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Eldena (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gorlosen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Grabow, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Karstädt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kremmin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Milow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Möllenbeck (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Muchow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Prislich (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Zierzow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Alt Zachun (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Bandenitz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Belsch (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Bobzin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Bresegard bei Picher (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gammelin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Groß Krams (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Hoort (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Hülseburg (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kirch Jesar (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kuhstorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Moraas (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Pätow-Steegen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Picher (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Pritzier (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Redefin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Strohkirchen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Toddin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Warlitz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Alt Krenzlin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Bresegard bei Eldena (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Göhlen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Groß Laasch (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Lübesse (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Lüblow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Rastow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Sülstorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Uelitz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Warlow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Wöbbelin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Blievenstorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Brenz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Neustadt-Glewe, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Domsühl (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Groß Godems (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Karrenzin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Lewitzrand (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Rom (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Spornitz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Stolpe (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Ziegendorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Zölkow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Obere Warnow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Barkhagen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Plau am See, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Ganzlin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Blankenberg (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Borkow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Brüel, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dabel (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Hohen Pritz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kobrow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kuhlen-Wendorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Mustin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Sternberg, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Weitendorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Witzin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kloster Tempzin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dümmer (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Holthusen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Klein Rogahn (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Pampow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Schossin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Stralendorf (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Warsow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Wittenförden (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Zülow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Wittenburg, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Wittendörp (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gallin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Kogel (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Lüttow-Valluhn (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Vellahn (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Zarrentin am Schaalsee, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Banzkow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Barnin (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Bülow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Cambs (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Crivitz, Stadt (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Demen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Dobin am See (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Friedrichsruhe (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Gneven (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Langen Brütz (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Leezen (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Pinnow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Plate (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Raben Steinfeld (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Sukow (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Tramm (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Zapel (Ludwigslust-Parchim - Mecklenburg-Vorpommern)": "130760000000", + "Chemnitz, Stadt": "145110000000", + "Amtsberg (Erzgebirgskreis - Sachsen)": "145210000000", + "Annaberg-Buchholz, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Aue-Bad Schlema, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Breitenbrunn/Erzgeb. (Erzgebirgskreis - Sachsen)": "145210000000", + "Crottendorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Drebach (Erzgebirgskreis - Sachsen)": "145210000000", + "Ehrenfriedersdorf, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Eibenstock, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Gelenau/Erzgeb. (Erzgebirgskreis - Sachsen)": "145210000000", + "Großolbersdorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Großrückerswalde (Erzgebirgskreis - Sachsen)": "145210000000", + "Grünhain-Beierfeld, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Hohndorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Jahnsdorf/Erzgeb. (Erzgebirgskreis - Sachsen)": "145210000000", + "Johanngeorgenstadt, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Jöhstadt, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Lauter-Bernsbach, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Lößnitz, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Marienberg, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Mildenau (Erzgebirgskreis - Sachsen)": "145210000000", + "Neukirchen/Erzgeb. (Erzgebirgskreis - Sachsen)": "145210000000", + "Oberwiesenthal, Kurort, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Oelsnitz/Erzgeb., Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Olbernhau, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Pockau-Lengefeld, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Raschau-Markersbach (Erzgebirgskreis - Sachsen)": "145210000000", + "Schneeberg, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Schönheide (Erzgebirgskreis - Sachsen)": "145210000000", + "Schwarzenberg/Erzgeb., Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Sehmatal (Erzgebirgskreis - Sachsen)": "145210000000", + "Stützengrün (Erzgebirgskreis - Sachsen)": "145210000000", + "Thalheim/Erzgeb., Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Thermalbad Wiesenbad (Erzgebirgskreis - Sachsen)": "145210000000", + "Thum, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Wolkenstein, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Bärenstein (Erzgebirgskreis - Sachsen)": "145210000000", + "Königswalde (Erzgebirgskreis - Sachsen)": "145210000000", + "Auerbach (Erzgebirgskreis - Sachsen)": "145210000000", + "Burkhardtsdorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Gornsdorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Geyer, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Tannenberg (Erzgebirgskreis - Sachsen)": "145210000000", + "Lugau/Erzgeb., Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Niederwürschnitz (Erzgebirgskreis - Sachsen)": "145210000000", + "Scheibenberg, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Schlettau, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Deutschneudorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Heidersdorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Seiffen/Erzgeb., Kurort (Erzgebirgskreis - Sachsen)": "145210000000", + "Niederdorf (Erzgebirgskreis - Sachsen)": "145210000000", + "Stollberg/Erzgeb., Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Gornau/Erzgeb. (Erzgebirgskreis - Sachsen)": "145210000000", + "Zschopau, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Bockau (Erzgebirgskreis - Sachsen)": "145210000000", + "Zschorlau (Erzgebirgskreis - Sachsen)": "145210000000", + "Elterlein, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Zwönitz, Stadt (Erzgebirgskreis - Sachsen)": "145210000000", + "Börnichen/Erzgeb. (Erzgebirgskreis - Sachsen)": "145210000000", + "Grünhainichen (Erzgebirgskreis - Sachsen)": "145210000000", + "Augustusburg, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Bobritzsch-Hilbersdorf (Mittelsachsen - Sachsen)": "145220000000", + "Brand-Erbisdorf, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Claußnitz (Mittelsachsen - Sachsen)": "145220000000", + "Döbeln, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Eppendorf (Mittelsachsen - Sachsen)": "145220000000", + "Erlau (Mittelsachsen - Sachsen)": "145220000000", + "Flöha, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Frankenberg/Sa., Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Frauenstein, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Freiberg, Stadt, Universitätsstadt (Mittelsachsen - Sachsen)": "145220000000", + "Geringswalde, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Großhartmannsdorf (Mittelsachsen - Sachsen)": "145220000000", + "Großschirma, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Großweitzschen (Mittelsachsen - Sachsen)": "145220000000", + "Hainichen, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Halsbrücke (Mittelsachsen - Sachsen)": "145220000000", + "Hartha, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Hartmannsdorf (Mittelsachsen - Sachsen)": "145220000000", + "Königshain-Wiederau (Mittelsachsen - Sachsen)": "145220000000", + "Kriebstein (Mittelsachsen - Sachsen)": "145220000000", + "Leisnig, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Leubsdorf (Mittelsachsen - Sachsen)": "145220000000", + "Lichtenau (Mittelsachsen - Sachsen)": "145220000000", + "Lunzenau, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Mulda/Sa. (Mittelsachsen - Sachsen)": "145220000000", + "Neuhausen/Erzgeb. (Mittelsachsen - Sachsen)": "145220000000", + "Niederwiesa (Mittelsachsen - Sachsen)": "145220000000", + "Oberschöna (Mittelsachsen - Sachsen)": "145220000000", + "Oederan, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Penig, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Rechenberg-Bienenmühle (Mittelsachsen - Sachsen)": "145220000000", + "Reinsberg (Mittelsachsen - Sachsen)": "145220000000", + "Rossau (Mittelsachsen - Sachsen)": "145220000000", + "Roßwein, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Striegistal (Mittelsachsen - Sachsen)": "145220000000", + "Waldheim, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Wechselburg (Mittelsachsen - Sachsen)": "145220000000", + "Burgstädt, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Mühlau (Mittelsachsen - Sachsen)": "145220000000", + "Taura (Mittelsachsen - Sachsen)": "145220000000", + "Lichtenberg/Erzgeb. (Mittelsachsen - Sachsen)": "145220000000", + "Weißenborn/Erzgeb. (Mittelsachsen - Sachsen)": "145220000000", + "Altmittweida (Mittelsachsen - Sachsen)": "145220000000", + "Mittweida, Stadt, Hochschulstadt (Mittelsachsen - Sachsen)": "145220000000", + "Ostrau (Mittelsachsen - Sachsen)": "145220000000", + "Zschaitz-Ottewig (Mittelsachsen - Sachsen)": "145220000000", + "Königsfeld (Mittelsachsen - Sachsen)": "145220000000", + "Rochlitz, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Seelitz (Mittelsachsen - Sachsen)": "145220000000", + "Zettlitz (Mittelsachsen - Sachsen)": "145220000000", + "Dorfchemnitz (Mittelsachsen - Sachsen)": "145220000000", + "Sayda, Stadt (Mittelsachsen - Sachsen)": "145220000000", + "Adorf/Vogtl., Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Auerbach/Vogtl., Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Bad Brambach (Vogtlandkreis - Sachsen)": "145230000000", + "Bad Elster, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Ellefeld (Vogtlandkreis - Sachsen)": "145230000000", + "Elsterberg, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Klingenthal, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Lengenfeld, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Markneukirchen, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Muldenhammer (Vogtlandkreis - Sachsen)": "145230000000", + "Neumark (Vogtlandkreis - Sachsen)": "145230000000", + "Pausa-Mühltroff, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Plauen, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Pöhl (Vogtlandkreis - Sachsen)": "145230000000", + "Rodewisch, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Rosenbach/Vogtl. (Vogtlandkreis - Sachsen)": "145230000000", + "Steinberg (Vogtlandkreis - Sachsen)": "145230000000", + "Weischlitz (Vogtlandkreis - Sachsen)": "145230000000", + "Falkenstein/Vogtl., Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Grünbach (Vogtlandkreis - Sachsen)": "145230000000", + "Neustadt/Vogtl. (Vogtlandkreis - Sachsen)": "145230000000", + "Limbach (Vogtlandkreis - Sachsen)": "145230000000", + "Netzschkau, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Bösenbrunn (Vogtlandkreis - Sachsen)": "145230000000", + "Eichigt (Vogtlandkreis - Sachsen)": "145230000000", + "Oelsnitz/Vogtl., Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Triebel/Vogtl. (Vogtlandkreis - Sachsen)": "145230000000", + "Heinsdorfergrund (Vogtlandkreis - Sachsen)": "145230000000", + "Reichenbach im Vogtland, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Mühlental (Vogtlandkreis - Sachsen)": "145230000000", + "Schöneck/Vogtl., Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Neuensalz (Vogtlandkreis - Sachsen)": "145230000000", + "Treuen, Stadt (Vogtlandkreis - Sachsen)": "145230000000", + "Bergen (Vogtlandkreis - Sachsen)": "145230000000", + "Theuma (Vogtlandkreis - Sachsen)": "145230000000", + "Tirpersdorf (Vogtlandkreis - Sachsen)": "145230000000", + "Werda (Vogtlandkreis - Sachsen)": "145230000000", + "Callenberg (Zwickau - Sachsen)": "145240000000", + "Fraureuth (Zwickau - Sachsen)": "145240000000", + "Gersdorf (Zwickau - Sachsen)": "145240000000", + "Glauchau, Stadt (Zwickau - Sachsen)": "145240000000", + "Hartenstein, Stadt (Zwickau - Sachsen)": "145240000000", + "Hohenstein-Ernstthal, Stadt (Zwickau - Sachsen)": "145240000000", + "Langenbernsdorf (Zwickau - Sachsen)": "145240000000", + "Langenweißbach (Zwickau - Sachsen)": "145240000000", + "Lichtentanne (Zwickau - Sachsen)": "145240000000", + "Mülsen (Zwickau - Sachsen)": "145240000000", + "Neukirchen/Pleiße (Zwickau - Sachsen)": "145240000000", + "Oberlungwitz, Stadt (Zwickau - Sachsen)": "145240000000", + "Reinsdorf (Zwickau - Sachsen)": "145240000000", + "Werdau, Stadt (Zwickau - Sachsen)": "145240000000", + "Wildenfels, Stadt (Zwickau - Sachsen)": "145240000000", + "Wilkau-Haßlau, Stadt (Zwickau - Sachsen)": "145240000000", + "Zwickau, Stadt (Zwickau - Sachsen)": "145240000000", + "Crimmitschau, Stadt (Zwickau - Sachsen)": "145240000000", + "Dennheritz (Zwickau - Sachsen)": "145240000000", + "Crinitzberg (Zwickau - Sachsen)": "145240000000", + "Hartmannsdorf b. Kirchberg (Zwickau - Sachsen)": "145240000000", + "Hirschfeld (Zwickau - Sachsen)": "145240000000", + "Kirchberg, Stadt (Zwickau - Sachsen)": "145240000000", + "Limbach-Oberfrohna, Stadt (Zwickau - Sachsen)": "145240000000", + "Niederfrohna (Zwickau - Sachsen)": "145240000000", + "Meerane, Stadt (Zwickau - Sachsen)": "145240000000", + "Schönberg (Zwickau - Sachsen)": "145240000000", + "Bernsdorf (Zwickau - Sachsen)": "145240000000", + "Lichtenstein/Sa., Stadt (Zwickau - Sachsen)": "145240000000", + "St. Egidien (Zwickau - Sachsen)": "145240000000", + "Oberwiera (Zwickau - Sachsen)": "145240000000", + "Remse (Zwickau - Sachsen)": "145240000000", + "Waldenburg, Stadt (Zwickau - Sachsen)": "145240000000", + "Dresden, Stadt": "146120000000", + "Arnsdorf (Bautzen - Sachsen)": "146250000000", + "Bautzen / Budyšin, Stadt (Bautzen - Sachsen)": "146250000000", + "Bernsdorf, Stadt (Bautzen - Sachsen)": "146250000000", + "Burkau (Bautzen - Sachsen)": "146250000000", + "Cunewalde (Bautzen - Sachsen)": "146250000000", + "Demitz-Thumitz (Bautzen - Sachsen)": "146250000000", + "Doberschau-Gaußig / Dobruša-Huska (Bautzen - Sachsen)": "146250000000", + "Elsterheide / Halštrowska Hola (Bautzen - Sachsen)": "146250000000", + "Elstra, Stadt (Bautzen - Sachsen)": "146250000000", + "Göda / Hodźij (Bautzen - Sachsen)": "146250000000", + "Großdubrau / Wulka Dubrawa (Bautzen - Sachsen)": "146250000000", + "Großröhrsdorf, Stadt (Bautzen - Sachsen)": "146250000000", + "Haselbachtal (Bautzen - Sachsen)": "146250000000", + "Hochkirch / Bukecy (Bautzen - Sachsen)": "146250000000", + "Hoyerswerda / Wojerecy, Stadt (Bautzen - Sachsen)": "146250000000", + "Kamenz / Kamjenc, Stadt (Bautzen - Sachsen)": "146250000000", + "Königswartha / Rakecy (Bautzen - Sachsen)": "146250000000", + "Kubschütz / Kubšicy (Bautzen - Sachsen)": "146250000000", + "Lauta, Stadt (Bautzen - Sachsen)": "146250000000", + "Lohsa / Łaz (Bautzen - Sachsen)": "146250000000", + "Malschwitz / Malešecy (Bautzen - Sachsen)": "146250000000", + "Neukirch/Lausitz (Bautzen - Sachsen)": "146250000000", + "Oßling (Bautzen - Sachsen)": "146250000000", + "Ottendorf-Okrilla (Bautzen - Sachsen)": "146250000000", + "Radeberg, Stadt (Bautzen - Sachsen)": "146250000000", + "Radibor / Radwor (Bautzen - Sachsen)": "146250000000", + "Schirgiswalde-Kirschau, Stadt (Bautzen - Sachsen)": "146250000000", + "Schmölln-Putzkau (Bautzen - Sachsen)": "146250000000", + "Schwepnitz (Bautzen - Sachsen)": "146250000000", + "Sohland a. d. Spree (Bautzen - Sachsen)": "146250000000", + "Spreetal / Sprjewiny Doł (Bautzen - Sachsen)": "146250000000", + "Steinigtwolmsdorf (Bautzen - Sachsen)": "146250000000", + "Wachau (Bautzen - Sachsen)": "146250000000", + "Weißenberg / Wóspork, Stadt (Bautzen - Sachsen)": "146250000000", + "Wilthen, Stadt (Bautzen - Sachsen)": "146250000000", + "Wittichenau / Kulow, Stadt (Bautzen - Sachsen)": "146250000000", + "Bischofswerda, Stadt (Bautzen - Sachsen)": "146250000000", + "Rammenau (Bautzen - Sachsen)": "146250000000", + "Frankenthal (Bautzen - Sachsen)": "146250000000", + "Großharthau (Bautzen - Sachsen)": "146250000000", + "Großpostwitz/O.L. / Budestecy (Bautzen - Sachsen)": "146250000000", + "Obergurig / Hornja Hórka (Bautzen - Sachsen)": "146250000000", + "Königsbrück, Stadt (Bautzen - Sachsen)": "146250000000", + "Laußnitz (Bautzen - Sachsen)": "146250000000", + "Neukirch (Bautzen - Sachsen)": "146250000000", + "Neschwitz / Njeswačidło (Bautzen - Sachsen)": "146250000000", + "Puschwitz / Bóšicy (Bautzen - Sachsen)": "146250000000", + "Großnaundorf (Bautzen - Sachsen)": "146250000000", + "Lichtenberg (Bautzen - Sachsen)": "146250000000", + "Ohorn (Bautzen - Sachsen)": "146250000000", + "Pulsnitz, Stadt (Bautzen - Sachsen)": "146250000000", + "Steina (Bautzen - Sachsen)": "146250000000", + "Crostwitz / Chrósćicy (Bautzen - Sachsen)": "146250000000", + "Nebelschütz / Njebjelčicy (Bautzen - Sachsen)": "146250000000", + "Panschwitz-Kuckau / Pančicy-Kukow (Bautzen - Sachsen)": "146250000000", + "Räckelwitz / Worklecy (Bautzen - Sachsen)": "146250000000", + "Ralbitz-Rosenthal / Ralbicy-Róžant (Bautzen - Sachsen)": "146250000000", + "Boxberg/O.L. / Hamor (Görlitz - Sachsen)": "146260000000", + "Ebersbach-Neugersdorf, Stadt (Görlitz - Sachsen)": "146260000000", + "Görlitz, Stadt (Görlitz - Sachsen)": "146260000000", + "Herrnhut, Stadt (Görlitz - Sachsen)": "146260000000", + "Kottmar (Görlitz - Sachsen)": "146260000000", + "Krauschwitz i.d. O.L. / Krušwica (Görlitz - Sachsen)": "146260000000", + "Leutersdorf (Görlitz - Sachsen)": "146260000000", + "Markersdorf (Görlitz - Sachsen)": "146260000000", + "Mittelherwigsdorf (Görlitz - Sachsen)": "146260000000", + "Niesky, Stadt (Görlitz - Sachsen)": "146260000000", + "Oderwitz (Görlitz - Sachsen)": "146260000000", + "Ostritz, Stadt (Görlitz - Sachsen)": "146260000000", + "Seifhennersdorf, Stadt (Görlitz - Sachsen)": "146260000000", + "Zittau, Stadt (Görlitz - Sachsen)": "146260000000", + "Bad Muskau / Mužakow, Stadt (Görlitz - Sachsen)": "146260000000", + "Gablenz / Jabłońc (Görlitz - Sachsen)": "146260000000", + "Bernstadt a. d. Eigen, Stadt (Görlitz - Sachsen)": "146260000000", + "Schönau-Berzdorf a. d. Eigen (Görlitz - Sachsen)": "146260000000", + "Großschönau (Görlitz - Sachsen)": "146260000000", + "Hainewalde (Görlitz - Sachsen)": "146260000000", + "Großschweidnitz (Görlitz - Sachsen)": "146260000000", + "Lawalde (Görlitz - Sachsen)": "146260000000", + "Löbau, Stadt (Görlitz - Sachsen)": "146260000000", + "Rosenbach (Görlitz - Sachsen)": "146260000000", + "Dürrhennersdorf (Görlitz - Sachsen)": "146260000000", + "Neusalza-Spremberg, Stadt (Görlitz - Sachsen)": "146260000000", + "Schönbach (Görlitz - Sachsen)": "146260000000", + "Bertsdorf-Hörnitz (Görlitz - Sachsen)": "146260000000", + "Jonsdorf, Kurort (Görlitz - Sachsen)": "146260000000", + "Olbersdorf (Görlitz - Sachsen)": "146260000000", + "Oybin (Görlitz - Sachsen)": "146260000000", + "Beiersdorf (Görlitz - Sachsen)": "146260000000", + "Oppach (Görlitz - Sachsen)": "146260000000", + "Königshain (Görlitz - Sachsen)": "146260000000", + "Reichenbach/O.L., Stadt (Görlitz - Sachsen)": "146260000000", + "Vierkirchen (Görlitz - Sachsen)": "146260000000", + "Kreba-Neudorf / Chrjebja-Nowa Wjes (Görlitz - Sachsen)": "146260000000", + "Rietschen / Rěčicy (Görlitz - Sachsen)": "146260000000", + "Hähnichen (Görlitz - Sachsen)": "146260000000", + "Rothenburg/O.L., Stadt (Görlitz - Sachsen)": "146260000000", + "Groß Düben / Dźěwin (Görlitz - Sachsen)": "146260000000", + "Schleife / Slepo (Görlitz - Sachsen)": "146260000000", + "Trebendorf / Trjebin (Görlitz - Sachsen)": "146260000000", + "Weißkeißel / Wuskidź (Görlitz - Sachsen)": "146260000000", + "Weißwasser/O.L., Stadt / Běła Woda (Görlitz - Sachsen)": "146260000000", + "Hohendubrau / Wysoka Dubrawa (Görlitz - Sachsen)": "146260000000", + "Mücka / Mikow (Görlitz - Sachsen)": "146260000000", + "Quitzdorf am See (Görlitz - Sachsen)": "146260000000", + "Waldhufen (Görlitz - Sachsen)": "146260000000", + "Horka (Görlitz - Sachsen)": "146260000000", + "Kodersdorf (Görlitz - Sachsen)": "146260000000", + "Neißeaue (Görlitz - Sachsen)": "146260000000", + "Schöpstal (Görlitz - Sachsen)": "146260000000", + "Coswig, Stadt (Meißen - Sachsen)": "146270000000", + "Diera-Zehren (Meißen - Sachsen)": "146270000000", + "Ebersbach (Meißen - Sachsen)": "146270000000", + "Gröditz, Stadt (Meißen - Sachsen)": "146270000000", + "Großenhain, Stadt (Meißen - Sachsen)": "146270000000", + "Hirschstein (Meißen - Sachsen)": "146270000000", + "Käbschütztal (Meißen - Sachsen)": "146270000000", + "Klipphausen (Meißen - Sachsen)": "146270000000", + "Lommatzsch, Stadt (Meißen - Sachsen)": "146270000000", + "Meißen, Stadt (Meißen - Sachsen)": "146270000000", + "Moritzburg (Meißen - Sachsen)": "146270000000", + "Niederau (Meißen - Sachsen)": "146270000000", + "Nossen, Stadt (Meißen - Sachsen)": "146270000000", + "Priestewitz (Meißen - Sachsen)": "146270000000", + "Radebeul, Stadt (Meißen - Sachsen)": "146270000000", + "Radeburg, Stadt (Meißen - Sachsen)": "146270000000", + "Riesa, Stadt (Meißen - Sachsen)": "146270000000", + "Stauchitz (Meißen - Sachsen)": "146270000000", + "Strehla, Stadt (Meißen - Sachsen)": "146270000000", + "Thiendorf (Meißen - Sachsen)": "146270000000", + "Weinböhla (Meißen - Sachsen)": "146270000000", + "Zeithain (Meißen - Sachsen)": "146270000000", + "Glaubitz (Meißen - Sachsen)": "146270000000", + "Nünchritz (Meißen - Sachsen)": "146270000000", + "Röderaue (Meißen - Sachsen)": "146270000000", + "Wülknitz (Meißen - Sachsen)": "146270000000", + "Lampertswalde (Meißen - Sachsen)": "146270000000", + "Schönfeld (Meißen - Sachsen)": "146270000000", + "Bannewitz (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Dippoldiswalde, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Dürrröhrsdorf-Dittersbach (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Freital, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Glashütte, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Heidenau, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Hohnstein, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Kreischa (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Neustadt in Sachsen, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Rabenau, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Sebnitz, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Stolpen, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Wilsdruff, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Altenberg, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Hermsdorf/Erzgeb. (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Bad Gottleuba-Berggießhübel, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Bahretal (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Liebstadt, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Bad Schandau, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Rathmannsdorf (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Reinhardtsdorf-Schöna (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Dohna, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Müglitztal (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Gohrisch (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Königstein/Sächs. Schw., Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Rathen, Kurort (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Rosenthal-Bielatal (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Struppen (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Lohmen (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Stadt Wehlen, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Dohma (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Pirna, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Hartmannsdorf-Reichenau (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Klingenberg (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Dorfhain (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Tharandt, Stadt (Sächsische Schweiz-Osterzgebirge - Sachsen)": "146280000000", + "Leipzig, Stadt": "147130000000", + "Bennewitz (Leipzig - Sachsen)": "147290000000", + "Böhlen, Stadt (Leipzig - Sachsen)": "147290000000", + "Borna, Stadt (Leipzig - Sachsen)": "147290000000", + "Borsdorf (Leipzig - Sachsen)": "147290000000", + "Brandis, Stadt (Leipzig - Sachsen)": "147290000000", + "Colditz, Stadt (Leipzig - Sachsen)": "147290000000", + "Frohburg, Stadt (Leipzig - Sachsen)": "147290000000", + "Geithain, Stadt (Leipzig - Sachsen)": "147290000000", + "Grimma, Stadt (Leipzig - Sachsen)": "147290000000", + "Groitzsch, Stadt (Leipzig - Sachsen)": "147290000000", + "Großpösna (Leipzig - Sachsen)": "147290000000", + "Kitzscher, Stadt (Leipzig - Sachsen)": "147290000000", + "Lossatal (Leipzig - Sachsen)": "147290000000", + "Machern (Leipzig - Sachsen)": "147290000000", + "Markkleeberg, Stadt (Leipzig - Sachsen)": "147290000000", + "Markranstädt, Stadt (Leipzig - Sachsen)": "147290000000", + "Neukieritzsch (Leipzig - Sachsen)": "147290000000", + "Regis-Breitingen, Stadt (Leipzig - Sachsen)": "147290000000", + "Rötha, Stadt (Leipzig - Sachsen)": "147290000000", + "Thallwitz (Leipzig - Sachsen)": "147290000000", + "Trebsen/Mulde, Stadt (Leipzig - Sachsen)": "147290000000", + "Wurzen, Stadt (Leipzig - Sachsen)": "147290000000", + "Zwenkau, Stadt (Leipzig - Sachsen)": "147290000000", + "Bad Lausick, Stadt (Leipzig - Sachsen)": "147290000000", + "Otterwisch (Leipzig - Sachsen)": "147290000000", + "Belgershain (Leipzig - Sachsen)": "147290000000", + "Naunhof, Stadt (Leipzig - Sachsen)": "147290000000", + "Parthenstein (Leipzig - Sachsen)": "147290000000", + "Elstertrebnitz (Leipzig - Sachsen)": "147290000000", + "Pegau, Stadt (Leipzig - Sachsen)": "147290000000", + "Bad Düben, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Belgern-Schildau, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Cavertitz (Nordsachsen - Sachsen)": "147300000000", + "Dahlen, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Delitzsch, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Doberschütz (Nordsachsen - Sachsen)": "147300000000", + "Eilenburg, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Laußig (Nordsachsen - Sachsen)": "147300000000", + "Liebschützberg (Nordsachsen - Sachsen)": "147300000000", + "Löbnitz (Nordsachsen - Sachsen)": "147300000000", + "Mockrehna (Nordsachsen - Sachsen)": "147300000000", + "Mügeln, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Naundorf (Nordsachsen - Sachsen)": "147300000000", + "Oschatz, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Rackwitz (Nordsachsen - Sachsen)": "147300000000", + "Schkeuditz, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Taucha, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Wermsdorf (Nordsachsen - Sachsen)": "147300000000", + "Wiedemar (Nordsachsen - Sachsen)": "147300000000", + "Arzberg (Nordsachsen - Sachsen)": "147300000000", + "Beilrode (Nordsachsen - Sachsen)": "147300000000", + "Dommitzsch, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Elsnig (Nordsachsen - Sachsen)": "147300000000", + "Trossin (Nordsachsen - Sachsen)": "147300000000", + "Krostitz (Nordsachsen - Sachsen)": "147300000000", + "Schönwölkau (Nordsachsen - Sachsen)": "147300000000", + "Dreiheide (Nordsachsen - Sachsen)": "147300000000", + "Torgau, Stadt (Nordsachsen - Sachsen)": "147300000000", + "Jesewitz (Nordsachsen - Sachsen)": "147300000000", + "Zschepplin (Nordsachsen - Sachsen)": "147300000000", + "Dessau-Roßlau, Stadt": "150010000000", + "Halle (Saale), Stadt": "150020000000", + "Magdeburg, Landeshauptstadt": "150030000000", + "Arendsee (Altmark), Stadt (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Gardelegen, Hansestadt (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Kalbe (Milde), Stadt (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Klötze, Stadt (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Salzwedel, Hansestadt (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Apenburg-Winterfeld, Flecken (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Beetzendorf (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Dähre (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Diesdorf, Flecken (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Jübar (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Kuhfelde (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Rohrberg (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Wallstawe (Altmarkkreis Salzwedel - Sachsen-Anhalt)": "150810000000", + "Aken (Elbe), Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Bitterfeld-Wolfen, Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Köthen (Anhalt), Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Muldestausee (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Osternienburger Land (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Raguhn-Jeßnitz, Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Sandersdorf-Brehna, Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Südliches Anhalt, Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Zerbst/Anhalt, Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Zörbig, Stadt (Anhalt-Bitterfeld - Sachsen-Anhalt)": "150820000000", + "Barleben (Börde - Sachsen-Anhalt)": "150830000000", + "Haldensleben, Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Hohe Börde (Börde - Sachsen-Anhalt)": "150830000000", + "Niedere Börde (Börde - Sachsen-Anhalt)": "150830000000", + "Oebisfelde-Weferlingen, Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Oschersleben (Bode), Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Sülzetal (Börde - Sachsen-Anhalt)": "150830000000", + "Wanzleben-Börde, Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Wolmirstedt, Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Angern (Börde - Sachsen-Anhalt)": "150830000000", + "Burgstall (Börde - Sachsen-Anhalt)": "150830000000", + "Colbitz (Börde - Sachsen-Anhalt)": "150830000000", + "Loitsche-Heinrichsberg (Börde - Sachsen-Anhalt)": "150830000000", + "Rogätz (Börde - Sachsen-Anhalt)": "150830000000", + "Westheide (Börde - Sachsen-Anhalt)": "150830000000", + "Zielitz (Börde - Sachsen-Anhalt)": "150830000000", + "Altenhausen (Börde - Sachsen-Anhalt)": "150830000000", + "Beendorf (Börde - Sachsen-Anhalt)": "150830000000", + "Bülstringen (Börde - Sachsen-Anhalt)": "150830000000", + "Calvörde (Börde - Sachsen-Anhalt)": "150830000000", + "Erxleben (Börde - Sachsen-Anhalt)": "150830000000", + "Flechtingen (Börde - Sachsen-Anhalt)": "150830000000", + "Ingersleben (Börde - Sachsen-Anhalt)": "150830000000", + "Eilsleben (Börde - Sachsen-Anhalt)": "150830000000", + "Harbke (Börde - Sachsen-Anhalt)": "150830000000", + "Hötensleben (Börde - Sachsen-Anhalt)": "150830000000", + "Sommersdorf (Börde - Sachsen-Anhalt)": "150830000000", + "Ummendorf (Börde - Sachsen-Anhalt)": "150830000000", + "Völpke (Börde - Sachsen-Anhalt)": "150830000000", + "Wefensleben (Börde - Sachsen-Anhalt)": "150830000000", + "Am Großen Bruch (Börde - Sachsen-Anhalt)": "150830000000", + "Ausleben (Börde - Sachsen-Anhalt)": "150830000000", + "Gröningen, Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Kroppenstedt, Stadt (Börde - Sachsen-Anhalt)": "150830000000", + "Elsteraue (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Hohenmölsen, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Lützen, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Naumburg (Saale), Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Teuchern, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Weißenfels, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Zeitz, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "An der Poststraße (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Bad Bibra, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Eckartsberga, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Finne (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Finneland (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Kaiserpfalz (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Lanitz-Hassel-Tal (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Droyßig (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Gutenborn (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Kretzschau (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Schnaudertal (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Wetterzeube (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Balgstädt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Freyburg (Unstrut), Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Gleina (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Goseck (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Karsdorf (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Laucha an der Unstrut, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Nebra (Unstrut), Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Meineweh (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Mertendorf (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Molauer Land (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Osterfeld, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Schönburg (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Stößen, Stadt (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Wethau (Burgenlandkreis - Sachsen-Anhalt)": "150840000000", + "Ballenstedt, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Blankenburg (Harz), Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Falkenstein/Harz, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Halberstadt, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Harzgerode, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Huy (Harz - Sachsen-Anhalt)": "150850000000", + "Ilsenburg (Harz), Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Nordharz (Harz - Sachsen-Anhalt)": "150850000000", + "Oberharz am Brocken, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Osterwieck, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Quedlinburg, Welterbestadt (Harz - Sachsen-Anhalt)": "150850000000", + "Thale, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Wernigerode, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Ditfurt (Harz - Sachsen-Anhalt)": "150850000000", + "Groß Quenstedt (Harz - Sachsen-Anhalt)": "150850000000", + "Harsleben (Harz - Sachsen-Anhalt)": "150850000000", + "Hedersleben (Harz - Sachsen-Anhalt)": "150850000000", + "Schwanebeck, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Selke-Aue (Harz - Sachsen-Anhalt)": "150850000000", + "Wegeleben, Stadt (Harz - Sachsen-Anhalt)": "150850000000", + "Biederitz (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Burg, Stadt (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Elbe-Parey (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Genthin, Stadt (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Gommern, Stadt (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Jerichow, Stadt (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Möckern, Stadt (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Möser (Jerichower Land - Sachsen-Anhalt)": "150860000000", + "Allstedt, Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Arnstein, Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Eisleben, Lutherstadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Gerbstedt, Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Hettstedt, Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Mansfeld, Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Sangerhausen, Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Seegebiet Mansfelder Land (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Südharz (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Berga (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Brücken-Hackpfüffel (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Edersleben (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Kelbra (Kyffhäuser), Stadt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Wallhausen (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Ahlsdorf (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Benndorf (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Blankenheim (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Bornstedt (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Helbra (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Hergisdorf (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Klostermansfeld (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Wimmelburg (Mansfeld-Südharz - Sachsen-Anhalt)": "150870000000", + "Bad Dürrenberg, Solestadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Bad Lauchstädt, Goethestadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Braunsbedra, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Kabelsketal (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Landsberg, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Leuna, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Wettin-Löbejün, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Merseburg, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Mücheln (Geiseltal), Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Petersberg (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Querfurt, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Salzatal (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Schkopau (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Teutschenthal (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Barnstädt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Farnstädt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Nemsdorf-Göhrendorf (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Obhausen (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Schraplau, Stadt (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Steigra (Saalekreis - Sachsen-Anhalt)": "150880000000", + "Aschersleben, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Barby, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Bernburg (Saale), Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Bördeland (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Calbe (Saale), Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Hecklingen, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Könnern, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Nienburg (Saale), Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Schönebeck (Elbe), Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Seeland, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Staßfurt, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Bördeaue (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Börde-Hakel (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Borne (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Egeln, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Wolmirsleben (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Alsleben (Saale), Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Giersleben (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Güsten, Stadt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Ilberstedt (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Plötzkau (Salzlandkreis - Sachsen-Anhalt)": "150890000000", + "Bismark (Altmark), Stadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Havelberg, Hansestadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Osterburg (Altmark), Hansestadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Stendal, Hansestadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Tangerhütte, Stadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Tangermünde, Stadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Arneburg, Stadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Eichstedt (Altmark) (Stendal - Sachsen-Anhalt)": "150900000000", + "Goldbeck (Stendal - Sachsen-Anhalt)": "150900000000", + "Hassel (Stendal - Sachsen-Anhalt)": "150900000000", + "Hohenberg-Krusemark (Stendal - Sachsen-Anhalt)": "150900000000", + "Iden (Stendal - Sachsen-Anhalt)": "150900000000", + "Rochau (Stendal - Sachsen-Anhalt)": "150900000000", + "Werben (Elbe), Hansestadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Kamern (Stendal - Sachsen-Anhalt)": "150900000000", + "Klietz (Stendal - Sachsen-Anhalt)": "150900000000", + "Sandau (Elbe), Stadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Schollene (Stendal - Sachsen-Anhalt)": "150900000000", + "Schönhausen (Elbe) (Stendal - Sachsen-Anhalt)": "150900000000", + "Wust-Fischbeck (Stendal - Sachsen-Anhalt)": "150900000000", + "Aland (Stendal - Sachsen-Anhalt)": "150900000000", + "Altmärkische Höhe (Stendal - Sachsen-Anhalt)": "150900000000", + "Altmärkische Wische (Stendal - Sachsen-Anhalt)": "150900000000", + "Seehausen (Altmark), Hansestadt (Stendal - Sachsen-Anhalt)": "150900000000", + "Zehrental (Stendal - Sachsen-Anhalt)": "150900000000", + "Annaburg, Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Bad Schmiedeberg, Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Coswig (Anhalt), Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Gräfenhainichen, Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Jessen (Elster), Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Kemberg, Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Oranienbaum-Wörlitz, Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Wittenberg, Lutherstadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Zahna-Elster, Stadt (Wittenberg - Sachsen-Anhalt)": "150910000000", + "Erfurt, Stadt": "160510000000", + "Gera, Stadt": "160520000000", + "Jena, Stadt": "160530000000", + "Suhl, Stadt": "160540000000", + "Weimar, Stadt": "160550000000", + "Heilbad Heiligenstadt, Stadt (Eichsfeld - Thüringen)": "160610000000", + "Niederorschel (Eichsfeld - Thüringen)": "160610000000", + "Leinefelde-Worbis, Stadt (Eichsfeld - Thüringen)": "160610000000", + "Am Ohmberg (Eichsfeld - Thüringen)": "160610000000", + "Sonnenstein (Eichsfeld - Thüringen)": "160610000000", + "Dingelstädt, Stadt (Eichsfeld - Thüringen)": "160610000000", + "Berlingerode (Eichsfeld - Thüringen)": "160610000000", + "Brehme (Eichsfeld - Thüringen)": "160610000000", + "Ecklingerode (Eichsfeld - Thüringen)": "160610000000", + "Ferna (Eichsfeld - Thüringen)": "160610000000", + "Tastungen (Eichsfeld - Thüringen)": "160610000000", + "Wehnde (Eichsfeld - Thüringen)": "160610000000", + "Teistungen (Eichsfeld - Thüringen)": "160610000000", + "Breitenworbis (Eichsfeld - Thüringen)": "160610000000", + "Buhla (Eichsfeld - Thüringen)": "160610000000", + "Gernrode (Eichsfeld - Thüringen)": "160610000000", + "Haynrode (Eichsfeld - Thüringen)": "160610000000", + "Kirchworbis (Eichsfeld - Thüringen)": "160610000000", + "Arenshausen (Eichsfeld - Thüringen)": "160610000000", + "Bornhagen (Eichsfeld - Thüringen)": "160610000000", + "Burgwalde (Eichsfeld - Thüringen)": "160610000000", + "Freienhagen (Eichsfeld - Thüringen)": "160610000000", + "Fretterode (Eichsfeld - Thüringen)": "160610000000", + "Gerbershausen (Eichsfeld - Thüringen)": "160610000000", + "Hohengandern (Eichsfeld - Thüringen)": "160610000000", + "Kirchgandern (Eichsfeld - Thüringen)": "160610000000", + "Lindewerra (Eichsfeld - Thüringen)": "160610000000", + "Marth (Eichsfeld - Thüringen)": "160610000000", + "Rohrberg (Eichsfeld - Thüringen)": "160610000000", + "Rustenfelde (Eichsfeld - Thüringen)": "160610000000", + "Schachtebich (Eichsfeld - Thüringen)": "160610000000", + "Wahlhausen (Eichsfeld - Thüringen)": "160610000000", + "Bodenrode-Westhausen (Eichsfeld - Thüringen)": "160610000000", + "Geisleden (Eichsfeld - Thüringen)": "160610000000", + "Glasehausen (Eichsfeld - Thüringen)": "160610000000", + "Heuthen (Eichsfeld - Thüringen)": "160610000000", + "Hohes Kreuz (Eichsfeld - Thüringen)": "160610000000", + "Reinholterode (Eichsfeld - Thüringen)": "160610000000", + "Steinbach (Eichsfeld - Thüringen)": "160610000000", + "Wingerode (Eichsfeld - Thüringen)": "160610000000", + "Asbach-Sickenberg (Eichsfeld - Thüringen)": "160610000000", + "Birkenfelde (Eichsfeld - Thüringen)": "160610000000", + "Dietzenrode/Vatterode (Eichsfeld - Thüringen)": "160610000000", + "Eichstruth (Eichsfeld - Thüringen)": "160610000000", + "Lenterode (Eichsfeld - Thüringen)": "160610000000", + "Lutter (Eichsfeld - Thüringen)": "160610000000", + "Mackenrode (Eichsfeld - Thüringen)": "160610000000", + "Röhrig (Eichsfeld - Thüringen)": "160610000000", + "Schönhagen (Eichsfeld - Thüringen)": "160610000000", + "Steinheuterode (Eichsfeld - Thüringen)": "160610000000", + "Thalwenden (Eichsfeld - Thüringen)": "160610000000", + "Uder (Eichsfeld - Thüringen)": "160610000000", + "Wüstheuterode (Eichsfeld - Thüringen)": "160610000000", + "Büttstedt (Eichsfeld - Thüringen)": "160610000000", + "Effelder (Eichsfeld - Thüringen)": "160610000000", + "Großbartloff (Eichsfeld - Thüringen)": "160610000000", + "Küllstedt (Eichsfeld - Thüringen)": "160610000000", + "Wachstedt (Eichsfeld - Thüringen)": "160610000000", + "Dieterode (Eichsfeld - Thüringen)": "160610000000", + "Geismar (Eichsfeld - Thüringen)": "160610000000", + "Kella (Eichsfeld - Thüringen)": "160610000000", + "Krombach (Eichsfeld - Thüringen)": "160610000000", + "Pfaffschwende (Eichsfeld - Thüringen)": "160610000000", + "Schwobfeld (Eichsfeld - Thüringen)": "160610000000", + "Sickerode (Eichsfeld - Thüringen)": "160610000000", + "Volkerode (Eichsfeld - Thüringen)": "160610000000", + "Wiesenfeld (Eichsfeld - Thüringen)": "160610000000", + "Schimberg (Eichsfeld - Thüringen)": "160610000000", + "Ellrich, Stadt (Nordhausen - Thüringen)": "160620000000", + "Nordhausen, Stadt (Nordhausen - Thüringen)": "160620000000", + "Sollstedt (Nordhausen - Thüringen)": "160620000000", + "Hohenstein (Nordhausen - Thüringen)": "160620000000", + "Werther (Nordhausen - Thüringen)": "160620000000", + "Harztor (Nordhausen - Thüringen)": "160620000000", + "Görsbach (Nordhausen - Thüringen)": "160620000000", + "Urbach (Nordhausen - Thüringen)": "160620000000", + "Heringen/Helme, Stadt (Nordhausen - Thüringen)": "160620000000", + "Großlohra (Nordhausen - Thüringen)": "160620000000", + "Kehmstedt (Nordhausen - Thüringen)": "160620000000", + "Kleinfurra (Nordhausen - Thüringen)": "160620000000", + "Lipprechterode (Nordhausen - Thüringen)": "160620000000", + "Niedergebra (Nordhausen - Thüringen)": "160620000000", + "Bleicherode, Stadt (Nordhausen - Thüringen)": "160620000000", + "Barchfeld-Immelborn (Wartburgkreis - Thüringen)": "160630000000", + "Treffurt, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Unterbreizbach (Wartburgkreis - Thüringen)": "160630000000", + "Vacha, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Wutha-Farnroda (Wartburgkreis - Thüringen)": "160630000000", + "Gerstungen (Wartburgkreis - Thüringen)": "160630000000", + "Hörselberg-Hainich (Wartburgkreis - Thüringen)": "160630000000", + "Bad Liebenstein, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Krayenberggemeinde (Wartburgkreis - Thüringen)": "160630000000", + "Werra-Suhl-Tal, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Eisenach, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Berka v. d. Hainich (Wartburgkreis - Thüringen)": "160630000000", + "Bischofroda (Wartburgkreis - Thüringen)": "160630000000", + "Frankenroda (Wartburgkreis - Thüringen)": "160630000000", + "Hallungen (Wartburgkreis - Thüringen)": "160630000000", + "Krauthausen (Wartburgkreis - Thüringen)": "160630000000", + "Lauterbach (Wartburgkreis - Thüringen)": "160630000000", + "Nazza (Wartburgkreis - Thüringen)": "160630000000", + "Amt Creuzburg, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Bad Salzungen, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Leimbach (Wartburgkreis - Thüringen)": "160630000000", + "Buttlar (Wartburgkreis - Thüringen)": "160630000000", + "Geisa, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Gerstengrund (Wartburgkreis - Thüringen)": "160630000000", + "Schleid (Wartburgkreis - Thüringen)": "160630000000", + "Ruhla, Stadt (Wartburgkreis - Thüringen)": "160630000000", + "Seebach (Wartburgkreis - Thüringen)": "160630000000", + "Dermbach (Wartburgkreis - Thüringen)": "160630000000", + "Empfertshausen (Wartburgkreis - Thüringen)": "160630000000", + "Oechsen (Wartburgkreis - Thüringen)": "160630000000", + "Weilar (Wartburgkreis - Thüringen)": "160630000000", + "Wiesenthal (Wartburgkreis - Thüringen)": "160630000000", + "Bad Langensalza, Stadt (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Dünwald (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Mühlhausen/Thüringen, Stadt (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Unstruttal (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Menteroda (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Anrode (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Bad Tennstedt, Stadt (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Ballhausen (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Blankenburg (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Bruchstedt (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Haussömmern (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Hornsömmern (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Kirchheilingen (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Kutzleben (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Mittelsömmern (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Sundhausen (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Tottleben (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Urleben (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Großvargula (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Herbsleben (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Rodeberg (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Südeichsfeld (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Kammerforst (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Oppershausen (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Vogtei (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Schönstedt (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Unstrut-Hainich (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Körner (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Marolterode (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Nottertal-Heilinger Höhen, Stadt (Unstrut-Hainich-Kreis - Thüringen)": "160640000000", + "Bad Frankenhausen/Kyffhäuser, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Helbedündorf (Kyffhäuserkreis - Thüringen)": "160650000000", + "Sondershausen, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Kyffhäuserland (Kyffhäuserkreis - Thüringen)": "160650000000", + "Roßleben-Wiehe, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Greußen, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Clingen, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Niederbösa (Kyffhäuserkreis - Thüringen)": "160650000000", + "Oberbösa (Kyffhäuserkreis - Thüringen)": "160650000000", + "Topfstedt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Trebra (Kyffhäuserkreis - Thüringen)": "160650000000", + "Wasserthaleben (Kyffhäuserkreis - Thüringen)": "160650000000", + "Westgreußen (Kyffhäuserkreis - Thüringen)": "160650000000", + "Abtsbessingen (Kyffhäuserkreis - Thüringen)": "160650000000", + "Bellstedt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Ebeleben, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Freienbessingen (Kyffhäuserkreis - Thüringen)": "160650000000", + "Holzsußra (Kyffhäuserkreis - Thüringen)": "160650000000", + "Rockstedt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Borxleben (Kyffhäuserkreis - Thüringen)": "160650000000", + "Gehofen (Kyffhäuserkreis - Thüringen)": "160650000000", + "Kalbsrieth (Kyffhäuserkreis - Thüringen)": "160650000000", + "Mönchpfiffel-Nikolausrieth (Kyffhäuserkreis - Thüringen)": "160650000000", + "Reinsdorf (Kyffhäuserkreis - Thüringen)": "160650000000", + "Artern, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Etzleben (Kyffhäuserkreis - Thüringen)": "160650000000", + "Oberheldrungen (Kyffhäuserkreis - Thüringen)": "160650000000", + "An der Schmücke, Stadt (Kyffhäuserkreis - Thüringen)": "160650000000", + "Floh-Seligenthal (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Oberhof, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Schmalkalden, Kurort, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Steinbach-Hallenberg, Kurort, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Brotterode-Trusetal, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Zella-Mehlis, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Rhönblick (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Grabfeld (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Birx (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Erbenhausen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Frankenheim/Rhön (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Oberweid (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Kaltennordheim, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Friedelshausen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Mehmels (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Schwallungen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Wasungen, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Belrieth (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Christes (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Dillstädt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Einhausen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Ellingshausen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Kühndorf (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Leutersdorf (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Neubrunn (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Obermaßfeld-Grimmenthal (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Ritschenhausen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Rohr (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Schwarza (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Utendorf (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Vachdorf (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Meiningen, Stadt (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Rippershausen (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Sülzfeld (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Untermaßfeld (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Breitungen/Werra (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Fambach (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Rosa (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Roßdorf (Schmalkalden-Meiningen - Thüringen)": "160660000000", + "Friedrichroda, Stadt (Gotha - Thüringen)": "160670000000", + "Gotha, Stadt (Gotha - Thüringen)": "160670000000", + "Bad Tabarz (Gotha - Thüringen)": "160670000000", + "Tambach-Dietharz/Thür. Wald, Stadt (Gotha - Thüringen)": "160670000000", + "Waltershausen, Stadt (Gotha - Thüringen)": "160670000000", + "Nesse-Apfelstädt (Gotha - Thüringen)": "160670000000", + "Hörsel (Gotha - Thüringen)": "160670000000", + "Bienstädt (Gotha - Thüringen)": "160670000000", + "Eschenbergen (Gotha - Thüringen)": "160670000000", + "Friemar (Gotha - Thüringen)": "160670000000", + "Molschleben (Gotha - Thüringen)": "160670000000", + "Nottleben (Gotha - Thüringen)": "160670000000", + "Pferdingsleben (Gotha - Thüringen)": "160670000000", + "Tröchtelborn (Gotha - Thüringen)": "160670000000", + "Tüttleben (Gotha - Thüringen)": "160670000000", + "Zimmernsupra (Gotha - Thüringen)": "160670000000", + "Dachwig (Gotha - Thüringen)": "160670000000", + "Döllstädt (Gotha - Thüringen)": "160670000000", + "Gierstädt (Gotha - Thüringen)": "160670000000", + "Großfahner (Gotha - Thüringen)": "160670000000", + "Tonna (Gotha - Thüringen)": "160670000000", + "Luisenthal (Gotha - Thüringen)": "160670000000", + "Ohrdruf, Stadt (Gotha - Thüringen)": "160670000000", + "Schwabhausen (Gotha - Thüringen)": "160670000000", + "Drei Gleichen (Gotha - Thüringen)": "160670000000", + "Sonneborn (Gotha - Thüringen)": "160670000000", + "Nessetal (Gotha - Thüringen)": "160670000000", + "Emleben (Gotha - Thüringen)": "160670000000", + "Herrenhof (Gotha - Thüringen)": "160670000000", + "Georgenthal (Gotha - Thüringen)": "160670000000", + "Kölleda, Stadt (Sömmerda - Thüringen)": "160680000000", + "Sömmerda, Stadt (Sömmerda - Thüringen)": "160680000000", + "Weißensee, Stadt (Sömmerda - Thüringen)": "160680000000", + "Buttstädt (Sömmerda - Thüringen)": "160680000000", + "Andisleben (Sömmerda - Thüringen)": "160680000000", + "Gebesee, Stadt (Sömmerda - Thüringen)": "160680000000", + "Ringleben (Sömmerda - Thüringen)": "160680000000", + "Walschleben (Sömmerda - Thüringen)": "160680000000", + "Büchel (Sömmerda - Thüringen)": "160680000000", + "Griefstedt (Sömmerda - Thüringen)": "160680000000", + "Günstedt (Sömmerda - Thüringen)": "160680000000", + "Riethgen (Sömmerda - Thüringen)": "160680000000", + "Kindelbrück (Sömmerda - Thüringen)": "160680000000", + "Großneuhausen (Sömmerda - Thüringen)": "160680000000", + "Kleinneuhausen (Sömmerda - Thüringen)": "160680000000", + "Ostramondra (Sömmerda - Thüringen)": "160680000000", + "Rastenberg, Stadt (Sömmerda - Thüringen)": "160680000000", + "Gangloffsömmern (Sömmerda - Thüringen)": "160680000000", + "Haßleben (Sömmerda - Thüringen)": "160680000000", + "Riethnordhausen (Sömmerda - Thüringen)": "160680000000", + "Schwerstedt (Sömmerda - Thüringen)": "160680000000", + "Straußfurt (Sömmerda - Thüringen)": "160680000000", + "Werningshausen (Sömmerda - Thüringen)": "160680000000", + "Wundersleben (Sömmerda - Thüringen)": "160680000000", + "Alperstedt (Sömmerda - Thüringen)": "160680000000", + "Eckstedt (Sömmerda - Thüringen)": "160680000000", + "Großmölsen (Sömmerda - Thüringen)": "160680000000", + "Großrudestedt (Sömmerda - Thüringen)": "160680000000", + "Kleinmölsen (Sömmerda - Thüringen)": "160680000000", + "Markvippach (Sömmerda - Thüringen)": "160680000000", + "Nöda (Sömmerda - Thüringen)": "160680000000", + "Ollendorf (Sömmerda - Thüringen)": "160680000000", + "Schloßvippach (Sömmerda - Thüringen)": "160680000000", + "Sprötau (Sömmerda - Thüringen)": "160680000000", + "Udestedt (Sömmerda - Thüringen)": "160680000000", + "Vogelsberg (Sömmerda - Thüringen)": "160680000000", + "Elxleben (Sömmerda - Thüringen)": "160680000000", + "Witterda (Sömmerda - Thüringen)": "160680000000", + "Eisfeld, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Hildburghausen, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Schleusegrund (Hildburghausen - Thüringen)": "160690000000", + "Schleusingen, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Veilsdorf (Hildburghausen - Thüringen)": "160690000000", + "Masserberg (Hildburghausen - Thüringen)": "160690000000", + "Römhild, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Ahlstädt (Hildburghausen - Thüringen)": "160690000000", + "Beinerstadt (Hildburghausen - Thüringen)": "160690000000", + "Bischofrod (Hildburghausen - Thüringen)": "160690000000", + "Dingsleben (Hildburghausen - Thüringen)": "160690000000", + "Ehrenberg (Hildburghausen - Thüringen)": "160690000000", + "Eichenberg (Hildburghausen - Thüringen)": "160690000000", + "Grimmelshausen (Hildburghausen - Thüringen)": "160690000000", + "Grub (Hildburghausen - Thüringen)": "160690000000", + "Henfstädt (Hildburghausen - Thüringen)": "160690000000", + "Kloster Veßra (Hildburghausen - Thüringen)": "160690000000", + "Lengfeld (Hildburghausen - Thüringen)": "160690000000", + "Marisfeld (Hildburghausen - Thüringen)": "160690000000", + "Oberstadt (Hildburghausen - Thüringen)": "160690000000", + "Reurieth (Hildburghausen - Thüringen)": "160690000000", + "Schmeheim (Hildburghausen - Thüringen)": "160690000000", + "St.Bernhard (Hildburghausen - Thüringen)": "160690000000", + "Themar, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Schlechtsart (Hildburghausen - Thüringen)": "160690000000", + "Schweickershausen (Hildburghausen - Thüringen)": "160690000000", + "Straufhain (Hildburghausen - Thüringen)": "160690000000", + "Ummerstadt, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Westhausen (Hildburghausen - Thüringen)": "160690000000", + "Heldburg, Stadt (Hildburghausen - Thüringen)": "160690000000", + "Brünn/Thür. (Hildburghausen - Thüringen)": "160690000000", + "Auengrund (Hildburghausen - Thüringen)": "160690000000", + "Arnstadt, Stadt (Ilm-Kreis - Thüringen)": "160700000000", + "Amt Wachsenburg (Ilm-Kreis - Thüringen)": "160700000000", + "Ilmenau, Stadt (Ilm-Kreis - Thüringen)": "160700000000", + "Stadtilm, Stadt (Ilm-Kreis - Thüringen)": "160700000000", + "Geratal (Ilm-Kreis - Thüringen)": "160700000000", + "Großbreitenbach, Stadt (Ilm-Kreis - Thüringen)": "160700000000", + "Elgersburg (Ilm-Kreis - Thüringen)": "160700000000", + "Martinroda (Ilm-Kreis - Thüringen)": "160700000000", + "Plaue, Stadt (Ilm-Kreis - Thüringen)": "160700000000", + "Alkersleben (Ilm-Kreis - Thüringen)": "160700000000", + "Bösleben-Wüllersleben (Ilm-Kreis - Thüringen)": "160700000000", + "Dornheim (Ilm-Kreis - Thüringen)": "160700000000", + "Elleben (Ilm-Kreis - Thüringen)": "160700000000", + "Elxleben (Ilm-Kreis - Thüringen)": "160700000000", + "Osthausen-Wülfershausen (Ilm-Kreis - Thüringen)": "160700000000", + "Witzleben (Ilm-Kreis - Thüringen)": "160700000000", + "Apolda, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Bad Berka, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Blankenhain, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Ilmtal-Weinstraße (Weimarer Land - Thüringen)": "160710000000", + "Grammetal (Weimarer Land - Thüringen)": "160710000000", + "Hohenfelden (Weimarer Land - Thüringen)": "160710000000", + "Klettbach (Weimarer Land - Thüringen)": "160710000000", + "Kranichfeld, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Nauendorf (Weimarer Land - Thüringen)": "160710000000", + "Rittersdorf (Weimarer Land - Thüringen)": "160710000000", + "Tonndorf (Weimarer Land - Thüringen)": "160710000000", + "Buchfart (Weimarer Land - Thüringen)": "160710000000", + "Döbritschen (Weimarer Land - Thüringen)": "160710000000", + "Frankendorf (Weimarer Land - Thüringen)": "160710000000", + "Großschwabhausen (Weimarer Land - Thüringen)": "160710000000", + "Hammerstedt (Weimarer Land - Thüringen)": "160710000000", + "Hetschburg (Weimarer Land - Thüringen)": "160710000000", + "Kapellendorf (Weimarer Land - Thüringen)": "160710000000", + "Kiliansroda (Weimarer Land - Thüringen)": "160710000000", + "Kleinschwabhausen (Weimarer Land - Thüringen)": "160710000000", + "Lehnstedt (Weimarer Land - Thüringen)": "160710000000", + "Magdala, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Mechelroda (Weimarer Land - Thüringen)": "160710000000", + "Mellingen (Weimarer Land - Thüringen)": "160710000000", + "Oettern (Weimarer Land - Thüringen)": "160710000000", + "Umpferstedt (Weimarer Land - Thüringen)": "160710000000", + "Vollersroda (Weimarer Land - Thüringen)": "160710000000", + "Wiegendorf (Weimarer Land - Thüringen)": "160710000000", + "Bad Sulza, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Eberstedt (Weimarer Land - Thüringen)": "160710000000", + "Großheringen (Weimarer Land - Thüringen)": "160710000000", + "Niedertrebra (Weimarer Land - Thüringen)": "160710000000", + "Obertrebra (Weimarer Land - Thüringen)": "160710000000", + "Rannstedt (Weimarer Land - Thüringen)": "160710000000", + "Schmiedehausen (Weimarer Land - Thüringen)": "160710000000", + "Ballstedt (Weimarer Land - Thüringen)": "160710000000", + "Ettersburg (Weimarer Land - Thüringen)": "160710000000", + "Neumark, Stadt (Weimarer Land - Thüringen)": "160710000000", + "Am Ettersberg (Weimarer Land - Thüringen)": "160710000000", + "Lauscha, Stadt (Sonneberg - Thüringen)": "160720000000", + "Schalkau, Stadt (Sonneberg - Thüringen)": "160720000000", + "Sonneberg, Stadt (Sonneberg - Thüringen)": "160720000000", + "Steinach, Stadt (Sonneberg - Thüringen)": "160720000000", + "Frankenblick (Sonneberg - Thüringen)": "160720000000", + "Föritztal (Sonneberg - Thüringen)": "160720000000", + "Goldisthal (Sonneberg - Thüringen)": "160720000000", + "Neuhaus am Rennweg, Stadt (Sonneberg - Thüringen)": "160720000000", + "Bad Blankenburg, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Rudolstadt, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Saalfeld/Saale, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Leutenberg, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Uhlstädt-Kirchhasel (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Unterwellenborn (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Gräfenthal, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Lehesten, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Probstzella (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Cursdorf (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Deesbach (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Döschnitz (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Katzhütte (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Meura (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Rohrbach (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Schwarzburg (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Sitzendorf (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Unterweißbach (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Schwarzatal, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Altenbeuthen (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Hohenwarte (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Kaulsdorf (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Drognitz (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Allendorf (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Bechstedt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Königsee, Stadt (Saalfeld-Rudolstadt - Thüringen)": "160730000000", + "Kahla, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Crossen an der Elster (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Hartmannsdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Heideland (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Rauda (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Silbitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Walpernhain (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Schkölen, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Bremsnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Eineborn (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Geisenhain (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Gneus (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Großbockedra (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Karlsdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Kleinbockedra (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Kleinebersdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Lippersdorf-Erdmannsdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Meusebach (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Oberbodnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Ottendorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Rattelsdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Rausdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Renthendorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Tautendorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Tissa (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Trockenborn-Wolfersdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Tröbnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Unterbodnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Waltersdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Weißbach (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Altenberga (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Bibra (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Bucha (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Eichenberg (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Freienorla (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Großeutersdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Großpürschütz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Gumperda (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Hummelshain (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Kleineutersdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Laasdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Lindig (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Milda (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Orlamünde, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Reinstädt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Rothenstein (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Schöps (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Seitenroda (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Sulza (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Zöllnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Hermsdorf, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Mörsdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Reichenbach (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Schleifreisen (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "St.Gangloff (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Dornburg-Camburg, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Frauenprießnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Golmsdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Großlöbichau (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Hainichen (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Jenalöbnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Lehesten (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Löberschütz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Neuengönna (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Tautenburg (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Thierschneck (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Wichmar (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Zimmern (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Möckern (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Ruttersdorf-Lotschen (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Stadtroda, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Bürgel, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Graitschen b. Bürgel (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Nausnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Poxdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Eisenberg, Stadt (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Gösen (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Hainspitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Mertendorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Petersberg (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Rauschwitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Albersdorf (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Bad Klosterlausnitz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Bobeck (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Scheiditz (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Schlöben (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Schöngleina (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Serba (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Tautenhain (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Waldeck (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Weißenborn (Saale-Holzland-Kreis - Thüringen)": "160740000000", + "Hirschberg, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Bad Lobenstein, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Pößneck, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Schleiz, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Gefell, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Tanna, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Wurzbach, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Remptendorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Saalburg-Ebersdorf, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Rosenthal am Rennsteig (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Dittersdorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Görkwitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Göschitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Kirschkau (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Löhma (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Moßbach (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Neundorf (bei Schleiz) (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Oettersdorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Plothen (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Pörmitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Tegau (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Volkmannsdorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Bodelwitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Döbritz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Gertewitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Grobengereuth (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Langenorla (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Lausnitz b. Neustadt an der Orla (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Nimritz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Oberoppurg (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Oppurg (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Quaschwitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Solkwitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Weira (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Wernburg (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Dreitzsch (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Geroda (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Lemnitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Miesitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Mittelpöllnitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Rosendorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Schmieritz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Tömmelsdorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Triptis, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Eßbach (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Gössitz (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Keila (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Moxa (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Paska (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Peuschen (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Ranis, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Schmorda (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Schöndorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Seisla (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Wilhelmsdorf (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Ziegenrück, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Krölpa (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Kospoda (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Neustadt an der Orla, Stadt (Saale-Orla-Kreis - Thüringen)": "160750000000", + "Berga/Elster, Stadt (Greiz - Thüringen)": "160760000000", + "Greiz, Stadt (Greiz - Thüringen)": "160760000000", + "Ronneburg, Stadt (Greiz - Thüringen)": "160760000000", + "Harth-Pöllnitz (Greiz - Thüringen)": "160760000000", + "Kraftsdorf (Greiz - Thüringen)": "160760000000", + "Auma-Weidatal, Stadt (Greiz - Thüringen)": "160760000000", + "Mohlsdorf-Teichwolframsdorf (Greiz - Thüringen)": "160760000000", + "Braunichswalde (Greiz - Thüringen)": "160760000000", + "Endschütz (Greiz - Thüringen)": "160760000000", + "Gauern (Greiz - Thüringen)": "160760000000", + "Hilbersdorf (Greiz - Thüringen)": "160760000000", + "Kauern (Greiz - Thüringen)": "160760000000", + "Linda b. Weida (Greiz - Thüringen)": "160760000000", + "Paitzdorf (Greiz - Thüringen)": "160760000000", + "Rückersdorf (Greiz - Thüringen)": "160760000000", + "Seelingstädt (Greiz - Thüringen)": "160760000000", + "Teichwitz (Greiz - Thüringen)": "160760000000", + "Wünschendorf/Elster (Greiz - Thüringen)": "160760000000", + "Bocka (Greiz - Thüringen)": "160760000000", + "Hundhaupten (Greiz - Thüringen)": "160760000000", + "Lederhose (Greiz - Thüringen)": "160760000000", + "Lindenkreuz (Greiz - Thüringen)": "160760000000", + "Münchenbernsdorf, Stadt (Greiz - Thüringen)": "160760000000", + "Saara (Greiz - Thüringen)": "160760000000", + "Schwarzbach (Greiz - Thüringen)": "160760000000", + "Zedlitz (Greiz - Thüringen)": "160760000000", + "Bethenhausen (Greiz - Thüringen)": "160760000000", + "Brahmenau (Greiz - Thüringen)": "160760000000", + "Großenstein (Greiz - Thüringen)": "160760000000", + "Hirschfeld (Greiz - Thüringen)": "160760000000", + "Korbußen (Greiz - Thüringen)": "160760000000", + "Pölzig (Greiz - Thüringen)": "160760000000", + "Reichstädt (Greiz - Thüringen)": "160760000000", + "Schwaara (Greiz - Thüringen)": "160760000000", + "Bad Köstritz, Stadt (Greiz - Thüringen)": "160760000000", + "Caaschwitz (Greiz - Thüringen)": "160760000000", + "Hartmannsdorf (Greiz - Thüringen)": "160760000000", + "Crimla (Greiz - Thüringen)": "160760000000", + "Weida, Stadt (Greiz - Thüringen)": "160760000000", + "Langenwolschendorf (Greiz - Thüringen)": "160760000000", + "Weißendorf (Greiz - Thüringen)": "160760000000", + "Zeulenroda-Triebes, Stadt (Greiz - Thüringen)": "160760000000", + "Hohenleuben, Stadt (Greiz - Thüringen)": "160760000000", + "Kühdorf (Greiz - Thüringen)": "160760000000", + "Langenwetzendorf (Greiz - Thüringen)": "160760000000", + "Altenburg, Stadt (Altenburger Land - Thüringen)": "160770000000", + "Lucka, Stadt (Altenburger Land - Thüringen)": "160770000000", + "Meuselwitz, Stadt (Altenburger Land - Thüringen)": "160770000000", + "Fockendorf (Altenburger Land - Thüringen)": "160770000000", + "Gerstenberg (Altenburger Land - Thüringen)": "160770000000", + "Haselbach (Altenburger Land - Thüringen)": "160770000000", + "Treben (Altenburger Land - Thüringen)": "160770000000", + "Windischleuba (Altenburger Land - Thüringen)": "160770000000", + "Göhren (Altenburger Land - Thüringen)": "160770000000", + "Göllnitz (Altenburger Land - Thüringen)": "160770000000", + "Kriebitzsch (Altenburger Land - Thüringen)": "160770000000", + "Lödla (Altenburger Land - Thüringen)": "160770000000", + "Mehna (Altenburger Land - Thüringen)": "160770000000", + "Monstab (Altenburger Land - Thüringen)": "160770000000", + "Rositz (Altenburger Land - Thüringen)": "160770000000", + "Starkenberg (Altenburger Land - Thüringen)": "160770000000", + "Heukewalde (Altenburger Land - Thüringen)": "160770000000", + "Jonaswalde (Altenburger Land - Thüringen)": "160770000000", + "Löbichau (Altenburger Land - Thüringen)": "160770000000", + "Posterstein (Altenburger Land - Thüringen)": "160770000000", + "Thonhausen (Altenburger Land - Thüringen)": "160770000000", + "Vollmershain (Altenburger Land - Thüringen)": "160770000000", + "Gößnitz, Stadt (Altenburger Land - Thüringen)": "160770000000", + "Heyersdorf (Altenburger Land - Thüringen)": "160770000000", + "Ponitz (Altenburger Land - Thüringen)": "160770000000", + "Göpfersdorf (Altenburger Land - Thüringen)": "160770000000", + "Langenleuba-Niederhain (Altenburger Land - Thüringen)": "160770000000", + "Nobitz (Altenburger Land - Thüringen)": "160770000000", + "Dobitschen (Altenburger Land - Thüringen)": "160770000000", + "Schmölln, Stadt (Altenburger Land - Thüringen)": "160770000000" +} diff --git a/tests/components/nina/fixtures/sample_labels.json b/tests/components/nina/fixtures/sample_labels.json deleted file mode 100644 index 80ee31cc79f..00000000000 --- a/tests/components/nina/fixtures/sample_labels.json +++ /dev/null @@ -1,225 +0,0 @@ -{ - "BBK-ISC-050": "Halten Sie Abflüsse und Schächte frei, damit das Wasser abfließen kann.", - "BBK-ISC-052": "Halten Sie Abstand zu Bäumen und Gebäuden, von denen sich Dachlawinen lösen können.", - "BBK-ISC-051": "Halten Sie Abstand zu beschädigten Gebäuden und Stromleitungen.", - "BBK-ISC-058": "Schützen Sie sich vor der Sonne.", - "BBK-ISC-057": "Nutzen Sie öffentliche Verkehrsmittel.", - "BBK-ISC-059": "Schützen Sie sich vor direkter Sonneneinstrahlung (durch Aufenthalt im Schatten, Bekleidung, Kopfbedeckung etc.).", - "BBK-ISC-054": "Begeben Sie sich wenn möglich in sichere Räume des Gebäudes auf der hangabgewandten Seite.", - "BBK-ISC-053": "Halten Sie Abstand zu Bäumen und Stromleitungen. Sie können unter der Schneelast abbrechen, entwurzeln bzw. abknicken.", - "BBK-ISC-056": "Achten Sie auf ausströmendes Gas. Ein Hinweis darauf können Zischgeräusche oder ein gastypischer Geruch sein. Benutzen Sie keine Streichhölzer, Feuerzeuge oder Ähnliches: Offenes Feuer kann in Kombination mit ausströmendem Gas zu Explosionen und Bränden führen.", - "BBK-ISC-055": "Achten Sie auf zusätzliche Gefahren, z.B. Elektrizität. Vor allem im Zusammenhang mit beschädigten Wasserrohren werden elektrische Leitungen zur Gefahr, weil das austretende Wasser den Strom leiten kann.", - "BBK-ISC-061": "Vermeiden Sie längere Aufenthalte und Aktivitäten im Freien.", - "BBK-ISC-060": "Halten Sie sich nach Möglichkeit in kühlen Räumen und Gebäuden auf.", - "BBK-ISC-063": "Trinken Sie viel Wasser und achten Sie auf leichtes Essen.", - "BBK-ISC-062": "Tragen Sie im Freien eine Sonnenbrille mit 100% UV-Schutz.", - "BBK-ISC-069": "Vermeiden Sie jeden Hautkontakt mit Leitungswasser. Stellen Sie die Wasserzufuhr zu Ihrem Haus ab.", - "BBK-ISC-068": "Trinken Sie nur Mineralwasser aus der Flasche.", - "BBK-ISC-065": "Suchen Sie höher liegende Gebiete auf und warten Sie ab. Flutwellen können noch über Stunden hinweg auftreten.", - "BBK-ISC-064": "Verlassen Sie das betroffene Gebiet sofort und suchen Sie höher liegende Gebiete auf.", - "version": "11", - "BBK-ISC-067": "Trinken Sie kein Leitungswasser.", - "BBK-ISC-066": "Kochen Sie das Wasser ab, bevor Sie es zum Trinken oder in der Küche verwenden.", - "BBK-ISC-072": "Suchen Sie Deckung, zum Beispiel unter einem stabilen Tisch. Warten Sie ab, bis das Erdbeben vorüber ist.", - "BBK-ISC-071": "Suchen Sie Deckung und warten Sie ab, bis das Erdbeben vorüber ist.", - "BBK-ISC-074": "Verlassen Sie sofort beschädigte Gebäude. Vorsicht vor herunterfallenden Objekten.", - "BBK-ISC-073": "Halten Sie sich von Glasflächen wie Fenstern und Glastüren fern. Es besteht Verletzungsgefahr durch Glassplitter.", - "BBK-ISC-070": "Nehmen Sie gefährdete Personen vorübergehend bei sich auf.", - "BBK-ISC-079": "Bereiten Sie sich auf einen möglichen Stromausfall vor: Überprüfen Sie Ihre Vorräte an Wasser, Lebensmitteln, Bargeld, Batterien und Medikamenten.", - "BBK-ISC-076": "Berühren Sie keine Trümmerteile.", - "BBK-ISC-075": "Benutzen Sie keine Fahrstühle.", - "BBK-ISC-078": "Seien Sie auf Nachbeben gefasst.", - "BBK-ISC-077": "Halten Sie Abstand von Erdspalten und Abhängen.", - "BBK-ISC-083": "Halten Sie sämtliche Zugangswege zur Brandstelle frei.", - "BBK-ISC-082": "Es besteht keine Gefahr.", - "BBK-ISC-085": "Suchen Sie Schutz in einem Gebäude.", - "BBK-ISC-084": "Betreten Sie keine verqualmten Räume. Dort können sich tödliche Gase bilden.", - "BBK-ISC-081": "Bleiben Sie im Gebäude und warten Sie auf weitere Informationen.", - "BBK-ISC-080": "Nutzen Sie Fahrrad- oder Motorradhelme, um Ihren Kopf vor herabfallendem Gestein zu schützen.", - "BBK-ISC-087": "Schließen Sie Fenster und Türen und schalten Sie Lüftungen und Klimaanlagen ab.", - "BBK-ISC-086": "Suchen Sie sofort Schutz in einem Gebäude.", - "BBK-ISC-089": "Werfen Sie keine brennenden Zigaretten weg.", - "BBK-ISC-088": "Bedecken Sie Mund und Nase mit einem improvisierten Atemschutz (Stofftuch, Kleidungsstück, OP-Maske).", - "BBK-ISC-014": "Wir informieren Sie, wenn die Gefahr vorüber ist.", - "BBK-ISC-135": "Vermeiden Sie Aktivitäten in der Gruppe wie Teamsportarten.", - "BBK-ISC-013": "Warnen Sie andere Personen, um den Zutritt zum Gefahrenbereich zu verhindern.", - "BBK-ISC-134": "Vermeiden Sie Körperkontakt mit anderen Personen wie Begrüßungsküsse und Händeschütteln.", - "BBK-ISC-016": "Folgen Sie den Anweisungen der Einsatzkräfte.", - "BBK-ISC-015": "Achten Sie auf Durchsagen von Polizei und Feuerwehr.", - "BBK-ISC-136": "Es besteht kein Handlungsbedarf.", - "BBK-ISC-010": "Falls möglich, informieren Sie sich in den Medien, zum Beispiel im Lokalradio.", - "BBK-ISC-131": "Berühren Sie keine toten Tiere. Melden Sie Funde von toten Wildtieren den Behörden.", - "BBK-ISC-130": "Halten Sie Abstand zu betroffenen Landwirtschaftsbetrieben und beachten Sie Absperrmaßnahmen der Behörden.", - "BBK-ISC-012": "Informieren Sie Ihre Nachbarn.", - "BBK-ISC-133": "Halten Sie mindestens einen Meter Abstand zu Gesprächspartnern.", - "BBK-ISC-011": "Hören Sie regionale Radiosender.", - "BBK-ISC-132": "Waschen Sie sich regelmäßig und gründlich die Hände.", - "BBK-ISC-007": "Suchen Sie Schutz. Vermeiden Sie Autofahrten.", - "BBK-ISC-128": "Halten Sie ausreichend Abstand zum Gebäude, um sich vor herabfallenden Trümmerteilen und Staubwolken zu schützen.", - "BBK-ISC-006": "Vermeiden Sie Autofahrten.", - "BBK-ISC-127": "Nehmen Sie JETZT die Jodtabletten gemäß Packungsbeilage ein.", - "BBK-ISC-009": "Informieren Sie sich in den Medien, zum Beispiel im Lokalradio.", - "BBK-ISC-008": "Schalten Sie das Autoradio ein und achten Sie auf weitere Informationen.", - "BBK-ISC-129": "Wenn möglich, desinfizieren Sie Ihre Hände immer nach Kontakt mit möglichen Überträgern.", - "BBK-ISC-025": "Schließen Sie alle Fenster und Türen.", - "BBK-ISC-024": "Sollten Sie Hilfe beim Verlassen Ihrer Wohnung benötigen, nehmen Sie Kontakt mit Ihrer Stadt unter der angegebenen Telefonnummer auf.", - "BBK-ISC-027": "Schließen Sie die Fenster, Roll- oder Fensterläden und halten Sie sich von ungeschützten Öffnungen fern.", - "BBK-ISC-026": "Schalten Sie die Belüftung aus und schließen Sie die Fenster.", - "BBK-ISC-021": "Helfen Sie Kindern und anderen hilfsbedürftigen Personen, aber ohne sich selbst zu gefährden.", - "BBK-ISC-020": "Leisten Sie bei Bedarf Erste Hilfe, jedoch ohne sich selbst in Gefahr zu begeben.", - "BBK-ISC-023": "Nehmen Sie nur das Notwendigste mit, insbesondere Ausweise und Bargeld.", - "BBK-ISC-022": "Bereiten Sie sich auf eine Evakuierung vor.", - "BBK-ISC-018": "Telefonieren Sie nur im äußersten Notfall, damit die Leitungen nicht zusammenbrechen.", - "BBK-ISC-017": "Wählen Sie nur in Notfällen den Notruf 110 (Polizei) und 112 (Feuerwehr).", - "BBK-ISC-019": "Falls Sie relevante Beobachtungen gemacht haben, informieren Sie die Polizei (110).", - "BBK-EVC-007": "Biologische Gefahr", - "BBK-EVC-005": "Ausfall Notruf", - "BBK-ISC-030": "Meiden Sie den Aufenthalt im Freien. Halten Sie Abstand zu Bäumen, Türmen und Masten. Halten Sie mindesten 20 m Abstand zu Hochspannungsleitungen. Achten Sie auf herumfliegende Gegenstände.", - "BBK-EVC-006": "Ausfall Telefonleitung", - "BBK-EVC-009": "Bomben-/Munitionsfund", - "BBK-ISC-036": "Vermeiden Sie alle Gegenstände mit Metallteilen wie Regenschirme oder Fahrräder.", - "BBK-ISC-035": "Nehmen Sie empfindliche Geräte vom Netz.", - "BBK-ISC-038": "Lassen Sie Haus- und Nutztiere nicht ins Freie.", - "BBK-ISC-037": "Baden und duschen Sie während eines Gewitters nicht. Baden und duschen kann lebensgefährlich sein.", - "BBK-EVC-003": "Ausfall Gasversorgung", - "BBK-ISC-032": "Meiden Sie sehr große Räume wie zum Beispiel Hallen, in denen das Dach nicht durch Säulen gestützt wird.", - "BBK-EVC-004": "Ausfall IT-Systeme", - "BBK-ISC-031": "Meiden Sie Räume unmittelbar unter dem Dachstuhl.", - "BBK-EVC-001": "Angriff auf IT-Systeme", - "BBK-ISC-034": "Wenn Sie sich in offenem Gelände aufhalten, gehen Sie mit eng zusammenstehenden Füßen, möglichst in einer Mulde, auf den Fußballen in die Hocke.", - "BBK-EVC-002": "Angriff mit Kernwaffen", - "BBK-ISC-033": "Wenn es nirgendwo Schutz gibt, legen Sie sich mit dem Gesicht auf den Boden und schützen Sie Kopf und Nacken mit den Händen.", - "BBK-ISC-029": "Suchen Sie geschützte Orte auf, an denen Sie nicht von Hagel getroffen werden können.", - "BBK-ISC-028": "Bleiben Sie im Gebäude und warten Sie auf Anweisungen.", - "BBK-EVC-018": "Erdbeben", - "BBK-EVC-019": "Erdrutsch", - "BBK-EVC-016": "Deichbruch", - "BBK-ISC-041": "Gehen Sie bei Überschwemmungsgefahr nicht in Keller oder Tiefgaragen.", - "BBK-EVC-017": "Demonstration", - "BBK-ISC-040": "Begeben Sie sich in höher liegende Gebäudeteile.", - "BBK-EVC-010": "Brandgase", - "BBK-ISC-047": "Gehen Sie nicht an Gewässer, die Hochwasser führen. Flutwellen können Sie überraschen und das Ufer kann einbrechen.", - "BBK-EVC-011": "Brandgefahr", - "BBK-ISC-046": "Schalten Sie Strom, Gas und Heizungen in gefährdeten Räumen ab. Eine Stromschlaggefahr besteht bereits bei Kondenswasser! Liegt der Stromkasten im überfluteten Raum, betreten Sie diesen nicht, sondern informieren Sie die Feuerwehr (112).", - "BBK-ISC-049": "Fahren Sie nicht durch überflutete Straßen. Schon eine geringe Wasserhöhe kann die Steuerung behindern.", - "BBK-ISC-048": "Schwimmen Sie nicht in überschwemmten Straßen! Auch das Durchschreiten von überschwemmten Unterführungen ist lebensgefährlich! Durch den Druck im Kanal können Schachtabdeckungen hochgedrückt werden. Dabei entsteht ein Sog, durch den eine Person angesaugt werden kann.", - "BBK-EVC-014": "Chemische Gefahr", - "BBK-ISC-043": "Trennen Sie Gas-, Wasser- und Stromleitungen von der Versorgung.", - "BBK-EVC-015": "Dammbruch", - "BBK-ISC-042": "Bringen Sie persönliche Wertgegenstände in höher liegende Gebäudeteile.", - "BBK-EVC-012": "Chemieunfall", - "BBK-ISC-045": "Schalten Sie Strom und Heizungen in gefährdeten Räumen ab. Eine Stromschlaggefahr besteht bereits bei Kondenswasser! Liegt der Stromkasten im überfluteten Raum, betreten Sie diesen nicht, sondern informieren Sie die Feuerwehr (112).", - "BBK-ISC-044": "Schließen Sie alle Gasleitungen.", - "BBK-ISC-039": "Suchen Sie sofort höher liegende Gebiete auf.", - "BBK-EVC-029": "Gefahrgutunfall", - "BBK-EVC-027": "Gasaustritt", - "BBK-EVC-028": "Gefahr durch Waffen", - "BBK-EVC-021": "Extrem heftiger Starkregen", - "BBK-EVC-022": "Extrem starke Schneeverwehungen", - "BBK-EVC-020": "Explosionsgefahr", - "BBK-EVC-025": "Flugzeugabsturz", - "BBK-EVC-026": "Frost", - "BBK-EVC-023": "Extreme Orkanböen", - "BBK-EVC-024": "Extremes Glatteis", - "BBK-EVC-038": "Hochwasser", - "BBK-EVC-039": "Hohe UV-Strahlung", - "BBK-EVC-032": "Glatteis", - "BBK-ISC-102": "Erkundigen Sie sich über den Standort der Informationsstellen, die von den Behörden eingerichtet wurden.", - "BBK-EVC-033": "Gletscherabbruch", - "BBK-ISC-101": "Überprüfen und ergänzen Sie Ihre Ausrüstung und Vorräte an Wasser, Lebensmittel, Medikamente, Bargeld und Batterien.", - "BBK-EVC-030": "Geruchsbelästigung", - "BBK-ISC-104": "Warnen Sie andere Personen. Fordern Sie diese zur Flucht auf.", - "BBK-EVC-031": "Gewitter", - "BBK-ISC-103": "Wir melden, wenn die Gefahr vorüber ist.", - "BBK-EVC-036": "Hagel", - "BBK-EVC-037": "Hitze", - "BBK-EVC-034": "Großbrand", - "BBK-ISC-100": "Besorgen Sie sich Batterien für Taschenlampen und Radios.", - "BBK-EVC-035": "Großveranstaltung", - "BBK-EVC-049": "Nebel", - "BBK-EVC-043": "Lawinengefahr", - "BBK-ISC-113": "Sofern Sie keine Möglichkeit haben, ein Gebäude zu erreichen, legen Sie sich flach auf den Boden und schützen Sie den Kopf mit den Händen.", - "BBK-EVC-044": "Lebensbedrohliche Lage", - "BBK-ISC-112": "Legen Sie sich flach auf den Boden und schützen Sie Ihren Kopf mit den Händen.", - "BBK-EVC-041": "Insektenplage", - "BBK-ISC-115": "Sofern Sie sich in einem Fahrzeug aufhalten: Halten Sie auf dem Seitenstreifen bzw. am Fahrbahnrand an. Wenn sich ein Gebäude in der Nähe befindet, suchen Sie in diesem Gebäude Schutz.", - "BBK-EVC-042": "Lärmbelästigung", - "BBK-ISC-114": "Halten Sie auf dem Seitenstreifen bzw. am Fahrbahnrand an. Verlassen Sie das Fahrzeug: Das Benzin im Tank könnte durch die Auswirkungen einer Explosion entzündet werden.", - "BBK-EVC-047": "Luftverschmutzung", - "BBK-EVC-048": "Meteoriteneinschlag", - "BBK-EVC-045": "Lebensmittelwarnung", - "BBK-ISC-111": "Legen Sie sich auf den Boden, entfernt von Fenstern und Türen.", - "BBK-EVC-046": "Luftangriff", - "BBK-ISC-110": "Gehen Sie sofort in einen unterirdischen oder einen innenliegenden Raum mit möglichst wenig Außenwänden, Fenstern und Türen. Meiden Sie Gebäudeteile mit großen Glasflächen. Nutzen Sie keine Aufzüge.", - "BBK-ISC-109": "Gehen Sie sofort in einen innenliegenden Raum mit möglichst wenig Außenwänden, Fenstern und Türen. Meiden Sie Gebäudeteile mit Glasflächen.", - "BBK-ISC-106": "Suchen Sie Schutz, wenn Sie das Gebiet nicht sofort verlassen können.", - "BBK-EVC-040": "Infektionsgefahr", - "BBK-ISC-105": "Verstecken Sie sich.", - "BBK-ISC-108": "Gehen Sie schnell in Innenräume.", - "BBK-ISC-107": "Gehen Sie auf Polizeikräfte ruhig und besonnen zu. Halten Sie dabei die Hände hoch.", - "BBK-EVC-054": "Schädlingsbefall", - "BBK-ISC-003": "Verlassen Sie sofort das betroffene Gebiet.", - "BBK-ISC-124": "Schwangere und Kinder bis 16 sollen sich in geschlossenen Räumen aufhalten.", - "BBK-EVC-055": "Schiffshavarie", - "BBK-ISC-002": "Meiden Sie den Gefährdungsbereich.", - "BBK-ISC-123": "Bedecken Sie Mund und Nase mit einem improvisierten Atemschutz (Stofftuch, Kleidungsstück, OP-Maske). Bewegen Sie sich möglichst quer zur Windrichtung, da Sie so am schnellsten den Gefahrenbereich mit einer möglichen Gefahrstoffwolke verlassen.", - "BBK-EVC-052": "Raketenangriff", - "BBK-ISC-005": "Passen Sie Ihr Verhalten im Straßenverkehr den Verhältnissen an.", - "BBK-ISC-126": "Halten Sie Jodtabletten bereit. Nehmen Sie die Jodtabletten jetzt NOCH NICHT ein. Wenn es erforderlich sein sollte, werden wir Sie rechtzeitig informieren.", - "BBK-EVC-053": "Satellitenabsturz", - "BBK-ISC-004": "Umfahren Sie das betroffene Gebiet weiträumig.", - "BBK-ISC-125": "Ziehen Sie vor Betreten des Gebäudes Ihre Oberbekleidung und die Schuhe aus und lassen Sie diese außerhalb des Gebäudes zurück. Es könnte sein, dass Sie bereits mit einem Gefahrstoff in Kontakt gekommen sind. Waschen Sie sich zuerst die Hände, dann Gesicht und Haare sowie die Nase und die Ohren.", - "BBK-EVC-058": "Schneeverwehungen", - "BBK-ISC-120": "Informieren Sie die Einsatzkräfte über Schäden und Trümmerteile.", - "BBK-EVC-059": "Sicherheitswarnung", - "BBK-EVC-056": "Schlammlawine", - "BBK-ISC-001": "Meiden Sie das betroffene Gebiet.", - "BBK-ISC-122": "Suchen Sie einen Kellerraum oder innenliegende Räume in unteren Stockwerken auf.", - "BBK-EVC-057": "Schneefall", - "BBK-ISC-121": "Informieren Sie die Einsatzkräfte über Schäden und Trümmerteile. Trümmerteile können zusätzliche Gefahren wie Brände und Explosionen auslösen.", - "BBK-EVC-050": "Probewarnung", - "BBK-ISC-117": "Falls Sie das Fahrzeug nicht verlassen können, senken Sie den Kopf und schützen Sie diesen mit den Händen. Schalten Sie das Autoradio ein und achten Sie auf weitere Informationen.", - "BBK-EVC-051": "Radiologische Gefahr", - "BBK-ISC-116": "Halten Sie auf dem Seitenstreifen bzw. am Fahrbahnrand an. Verlassen Sie das Fahrzeug: Das Benzin im Tank könnte durch die Auswirkungen einer Explosion entzündet werden. Wenn sich ein Gebäude in der Nähe befindet, suchen Sie in diesem Gebäude Schutz.", - "BBK-ISC-119": "Berühren Sie keine Gegenstände, die Ihnen verdächtig vorkommen: Es besteht die Gefahr weiterer Explosionen. Verlassen Sie umgehend den Bereich und teilen Sie die Position verdächtiger Gegenstände den Einsatzkräften mit.", - "BBK-ISC-118": "Verlassen Sie sofort den Ort des Einschlags und bedecken Sie Mund und Nase mit einem improvisierten Atemschutz (Stofftuch, Kleidungsstück, OP-Maske). Dies schützt Sie vor Stäuben, allerdings nicht vor gasförmigen Gefahrstoffen. Suchen Sie ein Gebäude auf. Bewegen Sie sich möglichst quer zur Windrichtung, da Sie so am schnellsten den Gefahrenbereich mit einer möglichen Gefahrstoffwolke verlassen.", - "BBK-ISC-094": "Feuern Sie Feuerwerkskörper nur mit Bewilligung der Gemeinde ab, halten Sie einen Sicherheitsabstand zum Wald ein und halten Sie Löschwasser bereit.", - "BBK-ISC-093": "Zünden Sie keine Feuerwerkskörper.", - "BBK-ISC-096": "Die Stromversorgung wird so schnell wie möglich wieder hergestellt.", - "BBK-ISC-095": "Die Störung wird so schnell wie möglich behoben.", - "BBK-ISC-090": "Werfen Sie keine brennenden Zigaretten und Streichhölzer weg.", - "BBK-ISC-092": "Verwenden Sie beim Grillen fest eingerichtete Feuerstellen. Versichern Sie sich, dass Ihr Feuer vollständig gelöscht ist, bevor Sie den Ort verlassen.", - "BBK-ISC-091": "Machen Sie im Freien kein Feuer.", - "BBK-EVC-065": "Sturmflut", - "BBK-EVC-066": "Sturzflut", - "BBK-EVC-063": "Stromausfall", - "BBK-EVC-064": "Sturm", - "BBK-EVC-069": "Trinkwasserverschmutzung", - "BBK-ISC-098": "Schalten Sie alle netzbetriebenen Geräte aus.", - "BBK-ISC-097": "Reduzieren Sie Ihren Stromverbrauch über Akkus und Batterien auf das Nötigste.", - "BBK-EVC-067": "Tierseuche", - "BBK-EVC-068": "Tornado", - "BBK-ISC-099": "Reduzieren Sie Ihren Wasserverbrauch auf das Nötigste.", - "BBK-EVC-061": "Sonnensturm", - "BBK-EVC-062": "Starkregen", - "BBK-EVC-060": "Sirenentest", - "BBK-EVC-999": "Ohne Benennung", - "BBK-EVC-076": "Vulkanausbruch", - "BBK-EVC-077": "Waldbrand", - "BBK-EVC-074": "Verkehrsunfall", - "BBK-EVC-075": "Verkehrswarnung", - "BBK-EVC-078": "Warnung", - "BBK-EVC-079": "Weltkriegsbombe", - "BBK-EVC-072": "Unfall Kernkraftwerk", - "BBK-EVC-073": "Ungeklärtes Abwasser", - "BBK-EVC-070": "Tsunami", - "BBK-EVC-071": "Überschwemmung", - "BBK-EVC-087": "Extreme Wettersituationen, bei denen verbreitet mit Leiterseilschwingungen zu rechnen ist (keine Medienalarmierung)", - "BBK-EVC-085": "Schweres Gewitter mit extrem großem Hagel", - "BBK-EVC-086": "Schweres Gewitter mit extremen Orkanböen", - "BBK-EVC-080": "Zugunfall", - "BBK-EVC-083": "Extrem ergiebiger Dauerregen", - "BBK-EVC-084": "Extrem starker Schneefall", - "BBK-EVC-081": "Gesundheitsgefährdung", - "BBK-EVC-082": "Schweres Gewitter mit extrem heftigem Starkregen" -} diff --git a/tests/components/nina/fixtures/sample_regions.json b/tests/components/nina/fixtures/sample_regions.json deleted file mode 100644 index 140feb39c3b..00000000000 --- a/tests/components/nina/fixtures/sample_regions.json +++ /dev/null @@ -1,11524 +0,0 @@ -{ - "metadaten": { - "kennung": "urn:de:bund:destatis:bevoelkerungsstatistik:schluessel:rs_2021-07-31", - "kennungInhalt": "urn:de:bund:destatis:bevoelkerungsstatistik:schluessel:rs", - "version": "2021-07-31", - "nameKurz": [{ "value": "Regionalschlüssel", "lang": null }], - "nameLang": [ - { - "value": "Gemeinden, dargestellt durch den Amtlichen Regionalschlüssel (ARS) des Statistischen Bundesamtes", - "lang": null - } - ], - "nameTechnisch": "Regionalschluessel", - "herausgebernameLang": [ - { "value": "Statistisches Bundesamt, Wiesbaden", "lang": null } - ], - "herausgebernameKurz": [{ "value": "Destatis", "lang": null }], - "beschreibung": [ - { - "value": "Diese Codeliste stellt alle Gemeinden Deutschlands durch den Amtlichen Regionalschlüssel (ARS) dar, wie im Gemeindeverzeichnis des Statistischen Bundesamtes enthalten. Darüber hinaus enthält die Codeliste für die Stadtstaaten Hamburg, Bremen und Berlin Einträge für Stadt-/Ortsteile bzw. Stadtbezirke. Diese Einträge sind mit einem entsprechenden Hinweis versehen.", - "lang": null - } - ], - "versionBeschreibung": [], - "aenderungZurVorversion": [ - { "value": "Mehrere Aenderungen", "lang": null } - ], - "handbuchVersion": "1.0", - "xoevHandbuch": false, - "gueltigAb": 1627682400000, - "bezugsorte": [] - }, - "spalten": [ - { - "spaltennameLang": "SCHLUESSEL", - "spaltennameTechnisch": "SCHLUESSEL", - "datentyp": "string", - "codeSpalte": true, - "verwendung": { "code": "REQUIRED" }, - "empfohleneCodeSpalte": true, - "sprache": null - }, - { - "spaltennameLang": "Bezeichnung", - "spaltennameTechnisch": "Bezeichnung", - "datentyp": "string", - "codeSpalte": false, - "verwendung": { "code": "REQUIRED" }, - "empfohleneCodeSpalte": false, - "sprache": null - }, - { - "spaltennameLang": "Hinweis", - "spaltennameTechnisch": "Hinweis", - "datentyp": "string", - "codeSpalte": false, - "verwendung": { "code": "OPTIONAL" }, - "empfohleneCodeSpalte": false, - "sprache": null - } - ], - "daten": [ - ["010010000000", "Flensburg, Stadt", null], - ["010020000000", "Kiel, Landeshauptstadt", null], - ["010030000000", "Lübeck, Hansestadt", null], - ["010040000000", "Neumünster, Stadt", null], - ["010510011011", "Brunsbüttel, Stadt", null], - ["010510044044", "Heide, Stadt", null], - ["010515163003", "Averlak", null], - ["010515163010", "Brickeln", null], - ["010515163012", "Buchholz", null], - ["010515163016", "Burg (Dithmarschen)", null], - ["010515163022", "Dingen", null], - ["010515163024", "Eddelak", null], - ["010515163026", "Eggstedt", null], - ["010515163032", "Frestedt", null], - ["010515163037", "Großenrade", null], - ["010515163051", "Hochdonn", null], - ["010515163064", "Kuden", null], - ["010515163089", "Quickborn", null], - ["010515163097", "Sankt Michaelisdonn", null], - ["010515163110", "Süderhastedt", null], - ["010515166021", "Diekhusen-Fahrstedt", null], - ["010515166034", "Friedrichskoog", null], - ["010515166046", "Helse", null], - ["010515166057", "Kaiser-Wilhelm-Koog", null], - ["010515166062", "Kronprinzenkoog", null], - ["010515166072", "Marne, Stadt", null], - ["010515166073", "Marnerdeich", null], - ["010515166076", "Neufeld", null], - ["010515166077", "Neufelderkoog", null], - ["010515166090", "Ramhusen", null], - ["010515166103", "Schmedeswurth", null], - ["010515166118", "Trennewurth", null], - ["010515166119", "Volsemenhusen", null], - ["010515169005", "Barkenholm", null], - ["010515169008", "Bergewöhrden", null], - ["010515169019", "Dellstedt", null], - ["010515169020", "Delve", null], - ["010515169023", "Dörpling", null], - ["010515169030", "Fedderingen", null], - ["010515169035", "Gaushorn", null], - ["010515169036", "Glüsing", null], - ["010515169038", "Groven", null], - ["010515169047", "Hemme", null], - ["010515169049", "Hennstedt", null], - ["010515169052", "Hövede", null], - ["010515169053", "Hollingstedt", null], - ["010515169058", "Karolinenkoog", null], - ["010515169060", "Kleve", null], - ["010515169061", "Krempel", null], - ["010515169065", "Lehe", null], - ["010515169068", "Linden", null], - ["010515169071", "Lunden", null], - ["010515169080", "Norderheistedt", null], - ["010515169088", "Pahlen", null], - ["010515169092", "Rehm-Flehde-Bargen", null], - ["010515169096", "Sankt Annen", null], - ["010515169100", "Schalkholz", null], - ["010515169102", "Schlichting", null], - ["010515169114", "Tellingstedt", null], - ["010515169117", "Tielenhemme", null], - ["010515169120", "Wallen", null], - ["010515169125", "Welmbüttel", null], - ["010515169131", "Westerborstel", null], - ["010515169133", "Wiemerstedt", null], - ["010515169136", "Wrohm", null], - ["010515169139", "Süderdorf", null], - ["010515169141", "Süderheistedt", null], - ["010515172048", "Hemmingstedt", null], - ["010515172067", "Lieth", null], - ["010515172069", "Lohe-Rickelshof", null], - ["010515172075", "Neuenkirchen", null], - ["010515172081", "Norderwöhrden", null], - ["010515172082", "Nordhastedt", null], - ["010515172087", "Ostrohe", null], - ["010515172107", "Stelle-Wittenwurth", null], - ["010515172113", "Wöhrden", null], - ["010515172122", "Weddingstedt", null], - ["010515172130", "Wesseln", null], - ["010515175001", "Albersdorf", null], - ["010515175002", "Arkebek", null], - ["010515175004", "Bargenstedt", null], - ["010515175006", "Barlt", null], - ["010515175015", "Bunsoh", null], - ["010515175017", "Busenwurth", null], - ["010515175027", "Elpersbüttel", null], - ["010515175028", "Epenwöhrden", null], - ["010515175039", "Gudendorf", null], - ["010515175054", "Immenstedt", null], - ["010515175063", "Krumstedt", null], - ["010515175074", "Meldorf, Stadt", null], - ["010515175078", "Nindorf", null], - ["010515175083", "Odderade", null], - ["010515175085", "Offenbüttel", null], - ["010515175086", "Osterrade", null], - ["010515175098", "Sarzbüttel", null], - ["010515175099", "Schafstedt", null], - ["010515175104", "Schrum", null], - ["010515175126", "Wennbüttel", null], - ["010515175134", "Windbergen", null], - ["010515175135", "Wolmersdorf", null], - ["010515175137", "Nordermeldorf", null], - ["010515175138", "Tensbüttel-Röst", null], - ["010515178013", "Büsum", null], - ["010515178014", "Büsumer Deichhausen", null], - ["010515178033", "Friedrichsgabekoog", null], - ["010515178043", "Hedwigenkoog", null], - ["010515178045", "Hellschen-Heringsand-Unterschaar", null], - ["010515178050", "Hillgroven", null], - ["010515178079", "Norddeich", null], - ["010515178084", "Oesterdeichstrich", null], - ["010515178093", "Reinsbüttel", null], - ["010515178105", "Schülp", null], - ["010515178108", "Strübbel", null], - ["010515178109", "Süderdeich", null], - ["010515178121", "Warwerort", null], - ["010515178127", "Wesselburen, Stadt", null], - ["010515178128", "Wesselburener Deichhausen", null], - ["010515178129", "Wesselburenerkoog", null], - ["010515178132", "Westerdeichstrich", null], - ["010515178140", "Oesterwurth", null], - ["010530032032", "Geesthacht, Stadt", null], - ["010530083083", "Lauenburg/ Elbe, Stadt", null], - ["010530090090", "Mölln, Stadt", null], - ["010530100100", "Ratzeburg, Stadt", null], - ["010530116116", "Schwarzenbek, Stadt", null], - ["010530129129", "Wentorf bei Hamburg", null], - ["010535308008", "Behlendorf", null], - ["010535308009", "Berkenthin", null], - ["010535308011", "Bliestorf", null], - ["010535308024", "Düchelsdorf", null], - ["010535308034", "Göldenitz", null], - ["010535308061", "Kastorf", null], - ["010535308067", "Klempau", null], - ["010535308075", "Krummesse", null], - ["010535308094", "Niendorf bei Berkenthin", null], - ["010535308103", "Rondeshagen", null], - ["010535308120", "Sierksrade", null], - ["010535313002", "Alt-Mölln", null], - ["010535313005", "Bälau", null], - ["010535313013", "Borstorf", null], - ["010535313014", "Breitenfelde", null], - ["010535313037", "Grambek", null], - ["010535313056", "Hornbek", null], - ["010535313084", "Lehmrade", null], - ["010535313095", "Niendorf/ Stecknitz", null], - ["010535313113", "Schretstaken", null], - ["010535313125", "Talkau", null], - ["010535313134", "Woltersdorf", null], - ["010535318010", "Besenthal", null], - ["010535318015", "Bröthen", null], - ["010535318020", "Büchen", null], - ["010535318029", "Fitzen", null], - ["010535318035", "Göttin", null], - ["010535318046", "Gudow", null], - ["010535318048", "Güster", null], - ["010535318064", "Klein Pampau", null], - ["010535318080", "Langenlehsten", null], - ["010535318092", "Müssen", null], - ["010535318104", "Roseburg", null], - ["010535318115", "Schulendorf", null], - ["010535318119", "Siebeneichen", null], - ["010535318126", "Tramm", null], - ["010535318132", "Witzeeze", null], - ["010535323003", "Aumühle", null], - ["010535323012", "Börnsen", null], - ["010535323023", "Dassendorf", null], - ["010535323028", "Escheburg", null], - ["010535323050", "Hamwarde", null], - ["010535323053", "Hohenhorn", null], - ["010535323072", "Kröppelshagen-Fahrendorf", null], - ["010535323131", "Wiershop", null], - ["010535323133", "Wohltorf", null], - ["010535323135", "Worth", null], - ["010535343006", "Basedow", null], - ["010535343019", "Buchhorst", null], - ["010535343022", "Dalldorf", null], - ["010535343058", "Juliusburg", null], - ["010535343073", "Krüzen", null], - ["010535343074", "Krukow", null], - ["010535343082", "Lanze", null], - ["010535343087", "Lütau", null], - ["010535343111", "Schnakenbek", null], - ["010535343128", "Wangelau", null], - ["010535358001", "Albsfelde", null], - ["010535358004", "Bäk", null], - ["010535358016", "Brunsmark", null], - ["010535358018", "Buchholz", null], - ["010535358026", "Einhaus", null], - ["010535358030", "Fredeburg", null], - ["010535358033", "Giesensdorf", null], - ["010535358040", "Groß Disnack", null], - ["010535358041", "Groß Grönau", null], - ["010535358043", "Groß Sarau", null], - ["010535358051", "Harmsdorf", null], - ["010535358054", "Hollenbek", null], - ["010535358057", "Horst", null], - ["010535358062", "Kittlitz", null], - ["010535358066", "Klein Zecher", null], - ["010535358078", "Kulpin", null], - ["010535358088", "Mechow", null], - ["010535358093", "Mustin", null], - ["010535358098", "Pogeez", null], - ["010535358102", "Römnitz", null], - ["010535358107", "Salem", null], - ["010535358110", "Schmilau", null], - ["010535358117", "Seedorf", null], - ["010535358123", "Sterley", null], - ["010535358136", "Ziethen", null], - ["010535373007", "Basthorst", null], - ["010535373017", "Brunstorf", null], - ["010535373021", "Dahmker", null], - ["010535373027", "Elmenhorst", null], - ["010535373031", "Fuhlenhagen", null], - ["010535373036", "Grabau", null], - ["010535373042", "Groß Pampau", null], - ["010535373045", "Grove", null], - ["010535373047", "Gülzow", null], - ["010535373049", "Hamfelde", null], - ["010535373052", "Havekost", null], - ["010535373059", "Kankelau", null], - ["010535373060", "Kasseburg", null], - ["010535373070", "Köthel", null], - ["010535373071", "Kollow", null], - ["010535373076", "Kuddewörde", null], - ["010535373089", "Möhnsen", null], - ["010535373091", "Mühlenrade", null], - ["010535373106", "Sahms", null], - ["010535391025", "Duvensee", null], - ["010535391038", "Grinau", null], - ["010535391039", "Groß Boden", null], - ["010535391044", "Groß Schenkenberg", null], - ["010535391068", "Klinkrade", null], - ["010535391069", "Koberg", null], - ["010535391077", "Kühsen", null], - ["010535391079", "Labenz", null], - ["010535391081", "Lankau", null], - ["010535391085", "Linau", null], - ["010535391086", "Lüchow", null], - ["010535391096", "Nusse", null], - ["010535391097", "Panten", null], - ["010535391099", "Poggensee", null], - ["010535391101", "Ritzerau", null], - ["010535391108", "Sandesneben", null], - ["010535391109", "Schiphorst", null], - ["010535391112", "Schönberg", null], - ["010535391114", "Schürensöhlen", null], - ["010535391118", "Siebenbäumen", null], - ["010535391121", "Sirksfelde", null], - ["010535391122", "Steinhorst", null], - ["010535391124", "Stubben", null], - ["010535391127", "Walksfelde", null], - ["010535391130", "Wentorf (Amt Sandesneben)", null], - ["010539105105", "Sachsenwald (Forstgutsbez.),gemfr.Geb.", null], - ["010540033033", "Friedrichstadt, Stadt", null], - ["010540056056", "Husum, Stadt", null], - ["010540108108", "Reußenköge", null], - ["010540138138", "Tönning, Stadt", null], - ["010540168168", "Sylt", null], - ["010545417035", "Garding, Kirchspiel", null], - ["010545417036", "Garding, Stadt", null], - ["010545417040", "Grothusenkoog", null], - ["010545417063", "Katharinenheerd", null], - ["010545417072", "Kotzenbüll", null], - ["010545417090", "Norderfriedrichskoog", null], - ["010545417095", "Oldenswort", null], - ["010545417100", "Osterhever", null], - ["010545417104", "Poppenbüll", null], - ["010545417113", "Sankt Peter-Ording", null], - ["010545417134", "Tating", null], - ["010545417135", "Tetenbüll", null], - ["010545417140", "Tümlauer Koog", null], - ["010545417145", "Vollerwiek", null], - ["010545417148", "Welt", null], - ["010545417150", "Westerhever", null], - ["010545439046", "Hörnum (Sylt)", null], - ["010545439061", "Kampen (Sylt)", null], - ["010545439078", "List auf Sylt", null], - ["010545439149", "Wenningstedt-Braderup (Sylt)", null], - ["010545453003", "Ahrenviöl", null], - ["010545453004", "Ahrenviölfeld", null], - ["010545453011", "Behrendorf", null], - ["010545453013", "Bondelum", null], - ["010545453041", "Haselund", null], - ["010545453057", "Immenstedt", null], - ["010545453079", "Löwenstedt", null], - ["010545453092", "Norstedt", null], - ["010545453101", "Oster-Ohrstedt", null], - ["010545453118", "Schwesing", null], - ["010545453123", "Sollwitt", null], - ["010545453144", "Viöl", null], - ["010545453152", "Wester-Ohrstedt", null], - ["010545459039", "Gröde", null], - ["010545459050", "Hallig Hooge", null], - ["010545459074", "Langeneß", null], - ["010545459103", "Pellworm", null], - ["010545488005", "Alkersum", null], - ["010545488015", "Borgsum", null], - ["010545488025", "Dunsum", null], - ["010545488083", "Midlum", null], - ["010545488085", "Nebel", null], - ["010545488087", "Nieblum", null], - ["010545488089", "Norddorf auf Amrum", null], - ["010545488094", "Oevenum", null], - ["010545488098", "Oldsum", null], - ["010545488129", "Süderende", null], - ["010545488143", "Utersum", null], - ["010545488158", "Witsum", null], - ["010545488160", "Wittdün auf Amrum", null], - ["010545488163", "Wrixum", null], - ["010545488164", "Wyk auf Föhr, Stadt", null], - ["010545489001", "Achtrup", null], - ["010545489009", "Aventoft", null], - ["010545489016", "Bosbüll", null], - ["010545489017", "Braderup", null], - ["010545489018", "Bramstedtlund", null], - ["010545489022", "Dagebüll", null], - ["010545489027", "Ellhöft", null], - ["010545489034", "Friedrich-Wilhelm-Lübke-Koog", null], - ["010545489048", "Holm", null], - ["010545489055", "Humptrup", null], - ["010545489062", "Karlum", null], - ["010545489065", "Klanxbüll", null], - ["010545489068", "Klixbüll", null], - ["010545489073", "Ladelund", null], - ["010545489076", "Leck", null], - ["010545489077", "Lexgaard", null], - ["010545489086", "Neukirchen", null], - ["010545489088", "Niebüll, Stadt", null], - ["010545489109", "Risum-Lindholm", null], - ["010545489110", "Rodenäs", null], - ["010545489124", "Sprakebüll", null], - ["010545489125", "Stadum", null], - ["010545489126", "Stedesand", null], - ["010545489131", "Süderlügum", null], - ["010545489136", "Tinningstedt", null], - ["010545489142", "Uphusum", null], - ["010545489154", "Westre", null], - ["010545489165", "Galmsbüll", null], - ["010545489166", "Emmelsbüll-Horsbüll", null], - ["010545489167", "Enge-Sande", null], - ["010545492007", "Arlewatt", null], - ["010545492023", "Drage", null], - ["010545492026", "Elisabeth-Sophien-Koog", null], - ["010545492032", "Fresendelf", null], - ["010545492042", "Hattstedt", null], - ["010545492043", "Hattstedtermarsch", null], - ["010545492052", "Horstedt", null], - ["010545492054", "Hude", null], - ["010545492070", "Koldenbüttel", null], - ["010545492084", "Mildstedt", null], - ["010545492091", "Nordstrand", null], - ["010545492096", "Oldersbek", null], - ["010545492097", "Olderup", null], - ["010545492099", "Ostenfeld (Husum)", null], - ["010545492105", "Ramstedt", null], - ["010545492106", "Rantrum", null], - ["010545492116", "Schwabstedt", null], - ["010545492119", "Seeth", null], - ["010545492120", "Simonsberg", null], - ["010545492130", "Süderhöft", null], - ["010545492132", "Südermarsch", null], - ["010545492141", "Uelvesbüll", null], - ["010545492156", "Winnert", null], - ["010545492157", "Wisch", null], - ["010545492159", "Wittbek", null], - ["010545492161", "Witzwort", null], - ["010545492162", "Wobbenbüll", null], - ["010545494002", "Ahrenshöft", null], - ["010545494006", "Almdorf", null], - ["010545494010", "Bargum", null], - ["010545494012", "Bohmstedt", null], - ["010545494014", "Bordelum", null], - ["010545494019", "Bredstedt, Stadt", null], - ["010545494020", "Breklum", null], - ["010545494024", "Drelsdorf", null], - ["010545494037", "Goldebek", null], - ["010545494038", "Goldelund", null], - ["010545494045", "Högel", null], - ["010545494059", "Joldelund", null], - ["010545494071", "Kolkerheide", null], - ["010545494075", "Langenhorn", null], - ["010545494080", "Lütjenholm", null], - ["010545494093", "Ockholm", null], - ["010545494121", "Sönnebüll", null], - ["010545494128", "Struckum", null], - ["010545494146", "Vollstedt", null], - ["010550001001", "Ahrensbök", null], - ["010550004004", "Bad Schwartau, Stadt", null], - ["010550007007", "Bosau", null], - ["010550010010", "Dahme", null], - ["010550012012", "Eutin, Stadt", null], - ["010550016016", "Grömitz", null], - ["010550018018", "Grube", null], - ["010550021021", "Heiligenhafen, Stadt", null], - ["010550025025", "Kellenhusen (Ostsee)", null], - ["010550028028", "Malente", null], - ["010550032032", "Neustadt in Holstein, Stadt", null], - ["010550033033", "Oldenburg in Holstein, Stadt", null], - ["010550035035", "Ratekau", null], - ["010550040040", "Stockelsdorf", null], - ["010550041041", "Süsel", null], - ["010550042042", "Timmendorfer Strand", null], - ["010550044044", "Scharbeutz", null], - ["010550046046", "Fehmarn, Stadt", null], - ["010555543014", "Göhl", null], - ["010555543015", "Gremersdorf", null], - ["010555543017", "Großenbrode", null], - ["010555543022", "Heringsdorf", null], - ["010555543031", "Neukirchen", null], - ["010555543043", "Wangels", null], - ["010555546006", "Beschendorf", null], - ["010555546011", "Damlos", null], - ["010555546020", "Harmsdorf", null], - ["010555546023", "Kabelhorst", null], - ["010555546027", "Lensahn", null], - ["010555546029", "Manhagen", null], - ["010555546036", "Riepsdorf", null], - ["010555591002", "Altenkrempe", null], - ["010555591024", "Kasseedorf", null], - ["010555591037", "Schashagen", null], - ["010555591038", "Schönwalde am Bungsberg", null], - ["010555591039", "Sierksdorf", null], - ["010560002002", "Barmstedt, Stadt", null], - ["010560005005", "Bönningstedt", null], - ["010560015015", "Elmshorn, Stadt", null], - ["010560018018", "Halstenbek", null], - ["010560021021", "Hasloh", null], - ["010560025025", "Helgoland", null], - ["010560039039", "Pinneberg, Stadt", null], - ["010560041041", "Quickborn, Stadt", null], - ["010560043043", "Rellingen", null], - ["010560044044", "Schenefeld, Stadt", null], - ["010560048048", "Tornesch, Stadt", null], - ["010560049049", "Uetersen, Stadt", null], - ["010560050050", "Wedel, Stadt", null], - ["010565616029", "Klein Nordende", null], - ["010565616030", "Klein Offenseth-Sparrieshoop", null], - ["010565616031", "Kölln-Reisiek", null], - ["010565616033", "Seester", null], - ["010565616042", "Raa-Besenbek", null], - ["010565616045", "Seestermühe", null], - ["010565616046", "Seeth-Ekholt", null], - ["010565636006", "Bokel", null], - ["010565636010", "Brande-Hörnerkirchen", null], - ["010565636038", "Osterhorn", null], - ["010565636051", "Westerhorn", null], - ["010565660003", "Bevern", null], - ["010565660004", "Bilsen", null], - ["010565660008", "Bokholt-Hanredder", null], - ["010565660011", "Bullenkuhlen", null], - ["010565660014", "Ellerhoop", null], - ["010565660017", "Groß Offenseth-Aspern", null], - ["010565660022", "Heede", null], - ["010565660026", "Hemdingen", null], - ["010565660034", "Langeln", null], - ["010565660035", "Lutzhorn", null], - ["010565687009", "Borstel-Hohenraden", null], - ["010565687013", "Ellerbek", null], - ["010565687032", "Kummerfeld", null], - ["010565687040", "Prisdorf", null], - ["010565687047", "Tangstedt", null], - ["010565690001", "Appen", null], - ["010565690016", "Groß Nordende", null], - ["010565690019", "Haselau", null], - ["010565690020", "Haseldorf", null], - ["010565690023", "Heidgraben", null], - ["010565690024", "Heist", null], - ["010565690027", "Hetlingen", null], - ["010565690028", "Holm", null], - ["010565690036", "Moorrege", null], - ["010565690037", "Neuendeich", null], - ["010570001001", "Ascheberg (Holstein)", null], - ["010570008008", "Bönebüttel", null], - ["010570009009", "Bösdorf", null], - ["010570057057", "Plön, Stadt", null], - ["010570062062", "Preetz, Stadt", null], - ["010570091091", "Schwentinental, Stadt", null], - ["010575727004", "Behrensdorf (Ostsee)", null], - ["010575727007", "Blekendorf", null], - ["010575727013", "Dannau", null], - ["010575727021", "Giekau", null], - ["010575727026", "Helmstorf", null], - ["010575727027", "Högsdorf", null], - ["010575727029", "Hohenfelde", null], - ["010575727030", "Hohwacht (Ostsee)", null], - ["010575727034", "Kirchnüchel", null], - ["010575727035", "Klamp", null], - ["010575727038", "Kletkamp", null], - ["010575727048", "Lütjenburg, Stadt", null], - ["010575727055", "Panker", null], - ["010575727076", "Schwartbuck", null], - ["010575727082", "Tröndel", null], - ["010575739015", "Dersau", null], - ["010575739017", "Dörnick", null], - ["010575739022", "Grebin", null], - ["010575739032", "Kalübbe", null], - ["010575739045", "Lebrade", null], - ["010575739053", "Nehmten", null], - ["010575739065", "Rantzau", null], - ["010575739067", "Rathjensdorf", null], - ["010575739089", "Wittmoldt", null], - ["010575747002", "Barmissen", null], - ["010575747010", "Boksee", null], - ["010575747011", "Bothkamp", null], - ["010575747023", "Großbarkau", null], - ["010575747031", "Honigsee", null], - ["010575747033", "Kirchbarkau", null], - ["010575747037", "Klein Barkau", null], - ["010575747042", "Kühren", null], - ["010575747046", "Lehmkuhlen", null], - ["010575747047", "Löptin", null], - ["010575747054", "Nettelsee", null], - ["010575747058", "Pohnsdorf", null], - ["010575747059", "Postfeld", null], - ["010575747066", "Rastorf", null], - ["010575747070", "Schellhorn", null], - ["010575747084", "Wahlstorf", null], - ["010575747086", "Warnau", null], - ["010575755003", "Barsbek", null], - ["010575755006", "Bendfeld", null], - ["010575755012", "Brodersdorf", null], - ["010575755018", "Fahren", null], - ["010575755020", "Fiefbergen", null], - ["010575755028", "Höhndorf", null], - ["010575755039", "Köhn", null], - ["010575755040", "Krokau", null], - ["010575755041", "Krummbek", null], - ["010575755043", "Laboe", null], - ["010575755049", "Lutterbek", null], - ["010575755056", "Passade", null], - ["010575755060", "Prasdorf", null], - ["010575755063", "Probsteierhagen", null], - ["010575755073", "Schönberg (Holstein)", null], - ["010575755078", "Stakendorf", null], - ["010575755079", "Stein", null], - ["010575755081", "Stoltenberg", null], - ["010575755087", "Wendtorf", null], - ["010575755088", "Wisch", null], - ["010575775016", "Dobersdorf", null], - ["010575775044", "Lammershagen", null], - ["010575775050", "Martensrade", null], - ["010575775052", "Mucheln", null], - ["010575775072", "Schlesen", null], - ["010575775077", "Selent", null], - ["010575775090", "Fargau-Pratjau", null], - ["010575782025", "Heikendorf", null], - ["010575782051", "Mönkeberg", null], - ["010575782074", "Schönkirchen", null], - ["010575785005", "Belau", null], - ["010575785024", "Großharrie", null], - ["010575785068", "Rendswühren", null], - ["010575785069", "Ruhwinkel", null], - ["010575785071", "Schillsdorf", null], - ["010575785080", "Stolpe", null], - ["010575785083", "Tasdorf", null], - ["010575785085", "Wankendorf", null], - ["010580005005", "Altenholz", null], - ["010580034034", "Büdelsdorf, Stadt", null], - ["010580043043", "Eckernförde, Stadt", null], - ["010580092092", "Kronshagen", null], - ["010580135135", "Rendsburg, Stadt", null], - ["010580169169", "Wasbek", null], - ["010585803001", "Achterwehr", null], - ["010585803028", "Bredenbek", null], - ["010585803050", "Felde", null], - ["010585803093", "Krummwisch", null], - ["010585803104", "Melsdorf", null], - ["010585803126", "Ottendorf", null], - ["010585803130", "Quarnbek", null], - ["010585803171", "Westensee", null], - ["010585822037", "Dänischenhagen", null], - ["010585822116", "Noer", null], - ["010585822150", "Schwedeneck", null], - ["010585822157", "Strande", null], - ["010585824051", "Felm", null], - ["010585824058", "Gettorf", null], - ["010585824096", "Lindau", null], - ["010585824110", "Neudorf-Bornstein", null], - ["010585824112", "Neuwittenbek", null], - ["010585824121", "Osdorf", null], - ["010585824142", "Schinkel", null], - ["010585824165", "Tüttendorf", null], - ["010585830019", "Böhnhusen", null], - ["010585830053", "Flintbek", null], - ["010585830145", "Schönhorst", null], - ["010585830160", "Techelsdorf", null], - ["010585833003", "Alt Duvenstedt", null], - ["010585833054", "Fockbek", null], - ["010585833118", "Nübbel", null], - ["010585833136", "Rickert", null], - ["010585847010", "Bargstall", null], - ["010585847029", "Breiholz", null], - ["010585847036", "Christiansholm", null], - ["010585847047", "Elsdorf-Westermühlen", null], - ["010585847055", "Friedrichsgraben", null], - ["010585847056", "Friedrichsholm", null], - ["010585847070", "Hamdorf", null], - ["010585847078", "Hohn", null], - ["010585847089", "Königshügel", null], - ["010585847097", "Lohe-Föhrden", null], - ["010585847129", "Prinzenmoor", null], - ["010585847154", "Sophienhamm", null], - ["010585853031", "Brinjahe", null], - ["010585853048", "Embühren", null], - ["010585853068", "Haale", null], - ["010585853071", "Hamweddel", null], - ["010585853075", "Hörsten", null], - ["010585853086", "Jevenstedt", null], - ["010585853101", "Luhnstedt", null], - ["010585853148", "Schülp b. Rendsburg", null], - ["010585853155", "Stafstedt", null], - ["010585853172", "Westerrönfeld", null], - ["010585859018", "Blumenthal", null], - ["010585859105", "Mielkendorf", null], - ["010585859107", "Molfsee", null], - ["010585859138", "Rodenbek", null], - ["010585859139", "Rumohr", null], - ["010585859141", "Schierensee", null], - ["010585864011", "Bargstedt", null], - ["010585864021", "Bokel", null], - ["010585864023", "Borgdorf-Seedorf", null], - ["010585864027", "Brammer", null], - ["010585864038", "Dätgen", null], - ["010585864045", "Eisendorf", null], - ["010585864046", "Ellerdorf", null], - ["010585864049", "Emkendorf", null], - ["010585864059", "Gnutz", null], - ["010585864065", "Groß Vollstedt", null], - ["010585864091", "Krogaspe", null], - ["010585864094", "Langwedel", null], - ["010585864117", "Nortorf, Stadt", null], - ["010585864120", "Oldenhütten", null], - ["010585864147", "Schülp b. Nortorf", null], - ["010585864163", "Timmaspe", null], - ["010585864168", "Warder", null], - ["010585888026", "Bovenau", null], - ["010585888073", "Haßmoor", null], - ["010585888122", "Ostenfeld (Rendsburg)", null], - ["010585888124", "Osterrönfeld", null], - ["010585888132", "Rade b. Rendsburg", null], - ["010585888140", "Schacht-Audorf", null], - ["010585888146", "Schülldorf", null], - ["010585889016", "Bissee", null], - ["010585889022", "Bordesholm", null], - ["010585889033", "Brügge", null], - ["010585889063", "Grevenkrug", null], - ["010585889064", "Groß Buchwald", null], - ["010585889076", "Hoffeld", null], - ["010585889098", "Loop", null], - ["010585889108", "Mühbrook", null], - ["010585889109", "Negenharrie", null], - ["010585889133", "Reesdorf", null], - ["010585889143", "Schmalstede", null], - ["010585889144", "Schönbek", null], - ["010585889153", "Sören", null], - ["010585889170", "Wattenbek", null], - ["010585890008", "Ascheffel", null], - ["010585890024", "Borgstedt", null], - ["010585890030", "Brekendorf", null], - ["010585890035", "Bünsdorf", null], - ["010585890039", "Damendorf", null], - ["010585890066", "Groß Wittensee", null], - ["010585890069", "Haby", null], - ["010585890080", "Holtsee", null], - ["010585890081", "Holzbunge", null], - ["010585890083", "Hütten", null], - ["010585890088", "Klein Wittensee", null], - ["010585890111", "Neu Duvenstedt", null], - ["010585890123", "Osterby", null], - ["010585890127", "Owschlag", null], - ["010585890152", "Sehestedt", null], - ["010585890175", "Ahlefeld-Bistensee", null], - ["010585893004", "Altenhof", null], - ["010585893012", "Barkelsby", null], - ["010585893032", "Brodersby", null], - ["010585893040", "Damp", null], - ["010585893042", "Dörphof", null], - ["010585893052", "Fleckeby", null], - ["010585893057", "Gammelby", null], - ["010585893067", "Güby", null], - ["010585893082", "Holzdorf", null], - ["010585893084", "Hummelfeld", null], - ["010585893087", "Karby", null], - ["010585893090", "Kosel", null], - ["010585893099", "Loose", null], - ["010585893102", "Goosefeld", null], - ["010585893137", "Rieseby", null], - ["010585893162", "Thumby", null], - ["010585893166", "Waabs", null], - ["010585893173", "Windeby", null], - ["010585893174", "Winnemark", null], - ["010585895007", "Arpsdorf", null], - ["010585895009", "Aukrug", null], - ["010585895013", "Beldorf", null], - ["010585895014", "Bendorf", null], - ["010585895015", "Beringstedt", null], - ["010585895025", "Bornholt", null], - ["010585895044", "Ehndorf", null], - ["010585895061", "Gokels", null], - ["010585895062", "Grauel", null], - ["010585895072", "Hanerau-Hademarschen", null], - ["010585895074", "Heinkenborstel", null], - ["010585895077", "Hohenwestedt", null], - ["010585895085", "Jahrsdorf", null], - ["010585895100", "Lütjenwestedt", null], - ["010585895103", "Meezen", null], - ["010585895106", "Mörel", null], - ["010585895113", "Nienborstel", null], - ["010585895115", "Nindorf", null], - ["010585895119", "Oldenbüttel", null], - ["010585895125", "Osterstedt", null], - ["010585895128", "Padenstedt", null], - ["010585895131", "Rade b. Hohenwestedt", null], - ["010585895134", "Remmels", null], - ["010585895151", "Seefeld", null], - ["010585895156", "Steenfeld", null], - ["010585895158", "Tackesdorf", null], - ["010585895159", "Tappendorf", null], - ["010585895161", "Thaden", null], - ["010585895164", "Todenbüttel", null], - ["010585895167", "Wapelfeld", null], - ["010590045045", "Kappeln, Stadt", null], - ["010590075075", "Schleswig, Stadt", null], - ["010590113113", "Glücksburg (Ostsee), Stadt", null], - ["010590120120", "Harrislee", null], - ["010590183183", "Handewitt", null], - ["010595912107", "Eggebek", null], - ["010595912128", "Janneby", null], - ["010595912131", "Jerrishoe", null], - ["010595912132", "Jörl", null], - ["010595912138", "Langstedt", null], - ["010595912162", "Sollerup", null], - ["010595912169", "Süderhackstedt", null], - ["010595912174", "Wanderup", null], - ["010595915012", "Borgwedel", null], - ["010595915018", "Busdorf", null], - ["010595915019", "Dannewerk", null], - ["010595915026", "Fahrdorf", null], - ["010595915032", "Geltorf", null], - ["010595915043", "Jagel", null], - ["010595915056", "Lottorf", null], - ["010595915078", "Selk", null], - ["010595919101", "Tastrup", null], - ["010595919103", "Ausacker", null], - ["010595919116", "Großsolt", null], - ["010595919126", "Hürup", null], - ["010595919127", "Husby", null], - ["010595919141", "Maasbüll", null], - ["010595919182", "Freienwill", null], - ["010595920002", "Arnis, Stadt", null], - ["010595920034", "Grödersby", null], - ["010595920067", "Oersberg", null], - ["010595920068", "Rabenkirchen-Faulück", null], - ["010595937106", "Dollerup", null], - ["010595937118", "Grundhof", null], - ["010595937137", "Langballig", null], - ["010595937145", "Munkbrarup", null], - ["010595937157", "Ringsberg", null], - ["010595937176", "Wees", null], - ["010595937178", "Westerholz", null], - ["010595940159", "Sieverstedt", null], - ["010595940171", "Tarp", null], - ["010595940184", "Oeversee", null], - ["010595949076", "Schnarup-Thumby", null], - ["010595949161", "Sörup", null], - ["010595949185", "Mittelangeln", null], - ["010595952105", "Böxlund", null], - ["010595952115", "Großenwiehe", null], - ["010595952123", "Hörup", null], - ["010595952124", "Holt", null], - ["010595952129", "Jardelund", null], - ["010595952143", "Medelby", null], - ["010595952144", "Meyn", null], - ["010595952149", "Nordhackstedt", null], - ["010595952151", "Osterby", null], - ["010595952158", "Schafflund", null], - ["010595952173", "Wallsbüll", null], - ["010595952177", "Weesby", null], - ["010595952179", "Lindewitt", null], - ["010595974006", "Böel", null], - ["010595974055", "Loit", null], - ["010595974060", "Mohrkirch", null], - ["010595974063", "Norderbrarup", null], - ["010595974065", "Nottfeld", null], - ["010595974070", "Rügge", null], - ["010595974072", "Saustrup", null], - ["010595974074", "Scheggerott", null], - ["010595974080", "Steinfeld", null], - ["010595974083", "Süderbrarup", null], - ["010595974094", "Ulsnis", null], - ["010595974095", "Wagersrott", null], - ["010595974187", "Boren", null], - ["010595987008", "Böklund", null], - ["010595987037", "Havetoft", null], - ["010595987042", "Idstedt", null], - ["010595987049", "Klappholz", null], - ["010595987062", "Neuberend", null], - ["010595987073", "Schaalby", null], - ["010595987081", "Stolk", null], - ["010595987082", "Struxdorf", null], - ["010595987084", "Süderfahrenstedt", null], - ["010595987086", "Taarstedt", null], - ["010595987090", "Tolk", null], - ["010595987093", "Uelsby", null], - ["010595987097", "Twedt", null], - ["010595987098", "Nübel", null], - ["010595987189", "Brodersby-Goltoft", null], - ["010595990102", "Ahneby", null], - ["010595990109", "Esgrus", null], - ["010595990112", "Gelting", null], - ["010595990121", "Hasselberg", null], - ["010595990136", "Kronsgaard", null], - ["010595990142", "Maasholm", null], - ["010595990147", "Nieby", null], - ["010595990148", "Niesgrau", null], - ["010595990152", "Pommerby", null], - ["010595990154", "Rabel", null], - ["010595990155", "Rabenholz", null], - ["010595990163", "Stangheck", null], - ["010595990164", "Steinberg", null], - ["010595990167", "Sterup", null], - ["010595990168", "Stoltebüll", null], - ["010595990186", "Steinbergkirche", null], - ["010595993010", "Bollingstedt", null], - ["010595993023", "Ellingstedt", null], - ["010595993039", "Hollingstedt", null], - ["010595993041", "Hüsby", null], - ["010595993044", "Jübek", null], - ["010595993057", "Lürschau", null], - ["010595993077", "Schuby", null], - ["010595993079", "Silberstedt", null], - ["010595993092", "Treia", null], - ["010595996001", "Alt Bennebek", null], - ["010595996005", "Bergenhusen", null], - ["010595996009", "Börm", null], - ["010595996020", "Dörpstedt", null], - ["010595996024", "Erfde", null], - ["010595996035", "Groß Rheide", null], - ["010595996050", "Klein Bennebek", null], - ["010595996051", "Klein Rheide", null], - ["010595996053", "Kropp", null], - ["010595996058", "Meggerdorf", null], - ["010595996087", "Tetenhusen", null], - ["010595996088", "Tielen", null], - ["010595996096", "Wohlde", null], - ["010595996188", "Stapel", null], - ["010600004004", "Bad Bramstedt, Stadt", null], - ["010600005005", "Bad Segeberg, Stadt", null], - ["010600019019", "Ellerau", null], - ["010600039039", "Henstedt-Ulzburg", null], - ["010600044044", "Kaltenkirchen, Stadt", null], - ["010600063063", "Norderstedt, Stadt", null], - ["010600092092", "Wahlstedt, Stadt", null], - ["010605005003", "Armstedt", null], - ["010605005009", "Bimöhlen", null], - ["010605005013", "Borstel", null], - ["010605005021", "Föhrden-Barl", null], - ["010605005023", "Fuhlendorf", null], - ["010605005027", "Großenaspe", null], - ["010605005031", "Hagen", null], - ["010605005033", "Hardebek", null], - ["010605005035", "Hasenkrug", null], - ["010605005037", "Heidmoor", null], - ["010605005040", "Hitzhusen", null], - ["010605005056", "Mönkloh", null], - ["010605005095", "Weddelbrook", null], - ["010605005099", "Wiemersdorf", null], - ["010605024012", "Bornhöved", null], - ["010605024017", "Damsdorf", null], - ["010605024026", "Gönnebek", null], - ["010605024072", "Schmalensee", null], - ["010605024080", "Stocksee", null], - ["010605024086", "Tarbek", null], - ["010605024087", "Tensfeld", null], - ["010605024089", "Trappenkamp", null], - ["010605034043", "Itzstedt", null], - ["010605034046", "Kayhude", null], - ["010605034058", "Nahe", null], - ["010605034065", "Oering", null], - ["010605034076", "Seth", null], - ["010605034085", "Sülfeld", null], - ["010605043002", "Alveslohe", null], - ["010605043034", "Hartenholm", null], - ["010605043036", "Hasenmoor", null], - ["010605043054", "Lentföhrden", null], - ["010605043064", "Nützen", null], - ["010605043073", "Schmalfeld", null], - ["010605048042", "Hüttblek", null], - ["010605048045", "Kattendorf", null], - ["010605048047", "Kisdorf", null], - ["010605048066", "Oersdorf", null], - ["010605048077", "Sievershütten", null], - ["010605048082", "Struvenhütten", null], - ["010605048084", "Stuvenborn", null], - ["010605048094", "Wakendorf II", null], - ["010605048100", "Winsen", null], - ["010605053007", "Bark", null], - ["010605053008", "Bebensee", null], - ["010605053022", "Fredesdorf", null], - ["010605053029", "Groß Niendorf", null], - ["010605053041", "Högersdorf", null], - ["010605053051", "Kükels", null], - ["010605053053", "Leezen", null], - ["010605053057", "Mözen", null], - ["010605053062", "Neversdorf", null], - ["010605053074", "Schwissel", null], - ["010605053088", "Todesfelde", null], - ["010605053101", "Wittenborn", null], - ["010605063011", "Boostedt", null], - ["010605063016", "Daldorf", null], - ["010605063028", "Groß Kummerfeld", null], - ["010605063038", "Heidmühlen", null], - ["010605063052", "Latendorf", null], - ["010605063068", "Rickling", null], - ["010605086006", "Bahrenhof", null], - ["010605086010", "Blunk", null], - ["010605086015", "Bühnsdorf", null], - ["010605086018", "Dreggers", null], - ["010605086020", "Fahrenkrug", null], - ["010605086024", "Geschendorf", null], - ["010605086025", "Glasau", null], - ["010605086030", "Groß Rönnau", null], - ["010605086048", "Klein Gladebrügge", null], - ["010605086049", "Klein Rönnau", null], - ["010605086050", "Krems II", null], - ["010605086059", "Negernbötel", null], - ["010605086060", "Nehms", null], - ["010605086061", "Neuengörs", null], - ["010605086067", "Pronstorf", null], - ["010605086069", "Rohlstorf", null], - ["010605086070", "Schackendorf", null], - ["010605086071", "Schieren", null], - ["010605086075", "Seedorf", null], - ["010605086079", "Stipsdorf", null], - ["010605086081", "Strukdorf", null], - ["010605086090", "Travenhorst", null], - ["010605086091", "Traventhal", null], - ["010605086093", "Wakendorf I", null], - ["010605086096", "Weede", null], - ["010605086097", "Wensin", null], - ["010605086098", "Westerrade", null], - ["010609014014", "Buchholz (Forstgutsbez.),gemfr. Gebiet", null], - ["010610029029", "Glückstadt, Stadt", null], - ["010610046046", "Itzehoe, Stadt", null], - ["010610113113", "Wilster, Stadt", null], - ["010615104005", "Auufer", null], - ["010615104016", "Breitenberg", null], - ["010615104017", "Breitenburg", null], - ["010615104053", "Kollmoor", null], - ["010615104058", "Kronsmoor", null], - ["010615104061", "Lägerdorf", null], - ["010615104068", "Moordiek", null], - ["010615104072", "Münsterdorf", null], - ["010615104079", "Oelixdorf", null], - ["010615104109", "Westermoor", null], - ["010615104115", "Wittenbergen", null], - ["010615134004", "Altenmoor", null], - ["010615134012", "Blomesche Wildnis", null], - ["010615134015", "Borsfleth", null], - ["010615134027", "Engelbrechtsche Wildnis", null], - ["010615134037", "Herzhorn", null], - ["010615134041", "Hohenfelde", null], - ["010615134044", "Horst (Holstein)", null], - ["010615134050", "Kiebitzreihe", null], - ["010615134054", "Krempdorf", null], - ["010615134074", "Neuendorf b. Elmshorn", null], - ["010615134101", "Sommerland", null], - ["010615134118", "Kollmar", null], - ["010615138008", "Bekdorf", null], - ["010615138010", "Bekmünde", null], - ["010615138024", "Drage", null], - ["010615138034", "Heiligenstedten", null], - ["010615138035", "Heiligenstedtenerkamp", null], - ["010615138039", "Hodorf", null], - ["010615138040", "Hohenaspe", null], - ["010615138045", "Huje", null], - ["010615138047", "Kaaks", null], - ["010615138052", "Kleve", null], - ["010615138059", "Krummendiek", null], - ["010615138065", "Lohbarbek", null], - ["010615138067", "Mehlbek", null], - ["010615138070", "Moorhusen", null], - ["010615138082", "Oldendorf", null], - ["010615138083", "Ottenbüttel", null], - ["010615138084", "Peissen", null], - ["010615138098", "Schlotfeld", null], - ["010615138100", "Silzen", null], - ["010615138114", "Winseldorf", null], - ["010615153006", "Bahrenfleth", null], - ["010615153022", "Dägeling", null], - ["010615153026", "Elskop", null], - ["010615153030", "Grevenkop", null], - ["010615153055", "Krempe, Stadt", null], - ["010615153056", "Kremperheide", null], - ["010615153057", "Krempermoor", null], - ["010615153073", "Neuenbrook", null], - ["010615153092", "Rethwisch", null], - ["010615153104", "Süderau", null], - ["010615168001", "Aasbüttel", null], - ["010615168003", "Agethorst", null], - ["010615168011", "Besdorf", null], - ["010615168013", "Bokelrehm", null], - ["010615168014", "Bokhorst", null], - ["010615168021", "Christinenthal", null], - ["010615168031", "Gribbohm", null], - ["010615168033", "Hadenfeld", null], - ["010615168043", "Holstenniendorf", null], - ["010615168048", "Kaisborstel", null], - ["010615168066", "Looft", null], - ["010615168076", "Nienbüttel", null], - ["010615168078", "Nutteln", null], - ["010615168081", "Oldenborstel", null], - ["010615168085", "Pöschendorf", null], - ["010615168087", "Puls", null], - ["010615168091", "Reher", null], - ["010615168097", "Schenefeld", null], - ["010615168105", "Vaale", null], - ["010615168106", "Vaalermoor", null], - ["010615168107", "Wacken", null], - ["010615168108", "Warringholz", null], - ["010615179002", "Aebtissinwisch", null], - ["010615179007", "Beidenfleth", null], - ["010615179018", "Brokdorf", null], - ["010615179020", "Büttel", null], - ["010615179023", "Dammfleth", null], - ["010615179025", "Ecklak", null], - ["010615179060", "Kudensee", null], - ["010615179062", "Landrecht", null], - ["010615179063", "Landscheide", null], - ["010615179077", "Nortorf", null], - ["010615179095", "Sankt Margarethen", null], - ["010615179102", "Stördorf", null], - ["010615179110", "Wewelsfleth", null], - ["010615179119", "Neuendorf-Sachsenbande", null], - ["010615189019", "Brokstedt", null], - ["010615189028", "Fitzbek", null], - ["010615189036", "Hennstedt", null], - ["010615189038", "Hingstheide", null], - ["010615189042", "Hohenlockstedt", null], - ["010615189049", "Kellinghusen, Stadt", null], - ["010615189064", "Lockstedt", null], - ["010615189071", "Mühlenbarbek", null], - ["010615189080", "Oeschebüttel", null], - ["010615189086", "Poyenberg", null], - ["010615189088", "Quarnstedt", null], - ["010615189089", "Rade", null], - ["010615189093", "Rosdorf", null], - ["010615189096", "Sarlhusen", null], - ["010615189103", "Störkathen", null], - ["010615189111", "Wiedenborstel", null], - ["010615189112", "Willenscharen", null], - ["010615189116", "Wrist", null], - ["010615189117", "Wulfsmoor", null], - ["010620001001", "Ahrensburg, Stadt", null], - ["010620004004", "Bad Oldesloe, Stadt", null], - ["010620006006", "Bargteheide, Stadt", null], - ["010620009009", "Barsbüttel", null], - ["010620018018", "Glinde, Stadt", null], - ["010620023023", "Großhansdorf", null], - ["010620053053", "Oststeinbek", null], - ["010620060060", "Reinbek, Stadt", null], - ["010620061061", "Reinfeld (Holstein), Stadt", null], - ["010620076076", "Tangstedt", null], - ["010620090090", "Ammersbek", null], - ["010625207019", "Grabau", null], - ["010625207046", "Meddewade", null], - ["010625207050", "Neritz", null], - ["010625207056", "Pölitz", null], - ["010625207062", "Rethwisch", null], - ["010625207065", "Rümpel", null], - ["010625207089", "Lasbek", null], - ["010625207091", "Steinburg", null], - ["010625207092", "Travenbrück", null], - ["010625218005", "Bargfeld-Stegen", null], - ["010625218014", "Delingsdorf", null], - ["010625218016", "Elmenhorst", null], - ["010625218027", "Hammoor", null], - ["010625218036", "Jersbek", null], - ["010625218051", "Nienwohld", null], - ["010625218078", "Todendorf", null], - ["010625218081", "Tremsbüttel", null], - ["010625244003", "Badendorf", null], - ["010625244008", "Barnitz", null], - ["010625244025", "Hamberge", null], - ["010625244031", "Heidekamp", null], - ["010625244032", "Heilshoop", null], - ["010625244039", "Klein Wesenberg", null], - ["010625244048", "Mönkhagen", null], - ["010625244059", "Rehhorst", null], - ["010625244083", "Westerau", null], - ["010625244087", "Zarpen", null], - ["010625244093", "Feldhorst", null], - ["010625244094", "Wesenberg", null], - ["010625262011", "Braak", null], - ["010625262035", "Hoisdorf", null], - ["010625262069", "Siek", null], - ["010625262071", "Stapelfeld", null], - ["010625262088", "Brunsbek", null], - ["010625270020", "Grande", null], - ["010625270021", "Grönwohld", null], - ["010625270022", "Großensee", null], - ["010625270026", "Hamfelde", null], - ["010625270033", "Hohenfelde", null], - ["010625270040", "Köthel", null], - ["010625270045", "Lütjensee", null], - ["010625270058", "Rausdorf", null], - ["010625270082", "Trittau", null], - ["010625270086", "Witzhave", null], - ["020000000000", "Hamburg, Freie und Hansestadt", null], - [ - "021010101101", - "Hamburg-Altstadt, OT 101", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "021010102102", - "Hamburg-Altstadt, OT 102", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["021020103103", "HafenCity, OT 103", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021020104104", "HafenCity, OT 104", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021030105105", "Neustadt, OT 105", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021030106106", "Neustadt, OT 106", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021030107107", "Neustadt, OT 107", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021030108108", "Neustadt, OT 108", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021040109109", "St. Pauli, OT 109", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021040110110", "St. Pauli, OT 110", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021040111111", "St. Pauli, OT 111", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021040112112", "St. Pauli, OT 112", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021050113113", "St. Georg, OT 113", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021050114114", "St. Georg, OT 114", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021060115115", "Hammerbrook, OT 115", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021060116116", "Hammerbrook, OT 116", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021060117117", "Hammerbrook, OT 117", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021060118118", "Hammerbrook, OT 118", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021070119119", "Borgfelde, OT 119", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021070120120", "Borgfelde, OT 120", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080121121", "Hamm, OT 121", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080122122", "Hamm, OT 122", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080123123", "Hamm, OT 123", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080124124", "Hamm, OT 124", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080125125", "Hamm, OT 125", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080126126", "Hamm, OT 126", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021080127127", "Hamm, OT 127", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021110128128", "Horn, OT 128", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021110129129", "Horn, OT 129", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021120130130", "Billstedt, OT 130", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021130131131", "Billbrook, OT 131", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "021140132132", - "Rothenburgsort, OT 132", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "021140133133", - "Rothenburgsort, OT 133", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["021150134134", "Veddel, OT 134", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "021160135135", - "Wilhelmsburg, OT 135", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "021160136136", - "Wilhelmsburg, OT 136", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "021160137137", - "Wilhelmsburg, OT 137", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "021170138138", - "Kleiner Grasbrook, OT 138", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["021180139139", "Steinwerder, OT 139", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["021190140140", "Waltershof, OT 140", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "021200141141", - "Finkenwerder, OT 141", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["021210142142", "Neuwerk, OT 142", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "021220150150", - "Seeleute/Binnenschiffer, OT 150", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022010201201", - "Altona-Altstadt, OT 201", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022010202202", - "Altona-Altstadt, OT 202", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022010203203", - "Altona-Altstadt, OT 203", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022010204204", - "Altona-Altstadt, OT 204", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022010205205", - "Altona-Altstadt, OT 205", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022010206206", - "Altona-Altstadt, OT 206", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "022020207207", - "Sternschanze, OT 207", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["022030208208", "Altona-Nord, OT 208", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022030209209", "Altona-Nord, OT 209", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022030210210", "Altona-Nord, OT 210", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022040211211", "Ottensen, OT 211", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022040212212", "Ottensen, OT 212", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022040213213", "Ottensen, OT 213", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022040214214", "Ottensen, OT 214", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022050215215", "Bahrenfeld, OT 215", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022050216216", "Bahrenfeld, OT 216", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022050217217", "Bahrenfeld, OT 217", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "022060218218", - "Groß Flottbek, OT 218", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["022070219219", "Othmarschen, OT 219", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022080220220", "Lurup, OT 220", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022090221221", "Osdorf, OT 221", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022100222222", "Nienstedten, OT 222", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022110223223", "Blankenese, OT 223", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022110224224", "Blankenese, OT 224", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022120225225", "Iserbrook, OT 225", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022130226226", "Sülldorf, OT 226", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["022140227227", "Rissen, OT 227", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010301301", "Eimsbüttel, OT 301", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010302302", "Eimsbüttel, OT 302", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010303303", "Eimsbüttel, OT 303", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010304304", "Eimsbüttel, OT 304", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010305305", "Eimsbüttel, OT 305", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010306306", "Eimsbüttel, OT 306", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010307307", "Eimsbüttel, OT 307", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010308308", "Eimsbüttel, OT 308", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010309309", "Eimsbüttel, OT 309", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023010310310", "Eimsbüttel, OT 310", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023020311311", "Rotherbaum, OT 311", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023020312312", "Rotherbaum, OT 312", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "023030313313", - "Harvestehude, OT 313", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "023030314314", - "Harvestehude, OT 314", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "023040315315", - "Hoheluft-West, OT 315", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "023040316316", - "Hoheluft-West, OT 316", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["023050317317", "Lokstedt, OT 317", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023060318318", "Niendorf, OT 318", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023070319319", "Schnelsen, OT 319", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023080320320", "Eidelstedt, OT 320", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["023090321321", "Stellingen, OT 321", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "024010401401", - "Hoheluft-Ost, OT 401", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "024010402402", - "Hoheluft-Ost, OT 402", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["024020403403", "Eppendorf, OT 403", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024020404404", "Eppendorf, OT 404", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024020405405", "Eppendorf, OT 405", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "024030406406", - "Gross Borstel, OT 406", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["024040407407", "Alsterdorf, OT 407", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024050408408", "Winterhude, OT 408", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024050409409", "Winterhude, OT 409", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024050410410", "Winterhude, OT 410", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024050411411", "Winterhude, OT 411", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024050412412", "Winterhude, OT 412", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024050413413", "Winterhude, OT 413", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024060414414", "Uhlenhorst, OT 414", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024060415415", "Uhlenhorst, OT 415", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024070416416", "Hohenfelde, OT 416", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024070417417", "Hohenfelde, OT 417", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024080418418", "Barmbek-Süd, OT 418", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024080419419", "Barmbek-Süd, OT 419", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024080420420", "Barmbek-Süd, OT 420", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024080421421", "Barmbek-Süd, OT 421", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024080422422", "Barmbek-Süd, OT 422", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024080423423", "Barmbek-Süd, OT 423", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024090424424", "Dulsberg, OT 424", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024090425425", "Dulsberg, OT 425", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "024100426426", - "Barmbek-Nord, OT 426", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "024100427427", - "Barmbek-Nord, OT 427", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "024100428428", - "Barmbek-Nord, OT 428", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "024100429429", - "Barmbek-Nord, OT 429", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["024110430430", "Ohlsdorf, OT 430", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024120431431", "Fuhlsbüttel, OT 431", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["024130432432", "Langenhorn, OT 432", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025010501501", "Eilbek, OT 501", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025010502502", "Eilbek, OT 502", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025010503503", "Eilbek, OT 503", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025010504504", "Eilbek, OT 504", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025020505505", "Wandsbek, OT 505", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025020506506", "Wandsbek, OT 506", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025020507507", "Wandsbek, OT 507", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025020508508", "Wandsbek, OT 508", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025020509509", "Wandsbek, OT 509", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025030510510", "Marienthal, OT 510", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025030511511", "Marienthal, OT 511", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025040512512", "Jenfeld, OT 512", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025050513513", "Tonndorf, OT 513", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "025060514514", - "Farmsen-Berne, OT 514", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["025070515515", "Bramfeld, OT 515", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025080516516", "Steilshoop, OT 516", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "025090517517", - "Wellingsbüttel, OT 517", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["025100518518", "Sasel, OT 518", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "025110519519", - "Poppenbüttel, OT 519", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "025120520520", - "Hummelsbüttel, OT 520", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - [ - "025130521521", - "Lemsahl-Mellingstedt, OT 521", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["025140522522", "Duvenstedt, OT 522", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "025150523523", - "Wohldorf-Ohlstedt, OT 523", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["025160524524", "Bergstedt, OT 524", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025170525525", "Volksdorf, OT 525", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["025180526526", "Rahlstedt, OT 526", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026010601601", "Lohbrügge, OT 601", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026020602602", "Bergedorf, OT 602", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026020603603", "Bergedorf, OT 603", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026030604604", "Curslack, OT 604", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026040605605", "Altengamme, OT 605", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026050606606", "Neuengamme, OT 606", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026060607607", "Kirchwerder, OT 607", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "026070608608", - "Ochsenwerder, OT 608", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["026080609609", "Reitbrook, OT 609", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026090610610", "Allermöhe, OT 610", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026100611611", "Billwerder, OT 611", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026110612612", "Moorfleet, OT 612", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026120613613", "Tatenberg, OT 613", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["026130614614", "Spadenland, OT 614", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "026140615615", - "Neuallermöhe, OT 615", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["027010701701", "Harburg, OT 701", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027010702702", "Harburg, OT 702", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027020703703", "Neuland, OT 703", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027030704704", "Gut Moor, OT 704", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027040705705", "Wilstorf, OT 705", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027050706706", "Rönneburg, OT 706", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027060707707", "Langenbek, OT 707", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027070708708", "Sinstorf, OT 708", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027080709709", "Marmstorf, OT 709", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027090710710", "Eissendorf, OT 710", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027100711711", "Heimfeld, OT 711", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027110712712", "Moorburg, OT 712", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027120713713", "Altenwerder, OT 713", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027130714714", "Hausbruch, OT 714", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "027140715715", - "Neugraben-Fischbek, OT 715", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["027150716716", "Francop, OT 716", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027160717717", "Neuenfelde, OT 717", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["027170718718", "Cranz, OT 718", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["031010000000", "Braunschweig, Stadt", null], - ["031020000000", "Salzgitter, Stadt", null], - ["031030000000", "Wolfsburg, Stadt", null], - ["031510009009", "Gifhorn, Stadt", null], - ["031510025025", "Sassenburg", null], - ["031510040040", "Wittingen, Stadt", null], - ["031515401002", "Barwedel", null], - ["031515401004", "Bokensdorf", null], - ["031515401014", "Jembke", null], - ["031515401020", "Osloß", null], - ["031515401030", "Tappenbeck", null], - ["031515401039", "Weyhausen", null], - ["031515402003", "Bergfeld", null], - ["031515402005", "Brome, Flecken", null], - ["031515402008", "Ehra-Lessien", null], - ["031515402021", "Parsau", null], - ["031515402024", "Rühen", null], - ["031515402031", "Tiddische", null], - ["031515402032", "Tülau", null], - ["031515403007", "Dedelstorf", null], - ["031515403011", "Hankensbüttel", null], - ["031515403019", "Obernholz", null], - ["031515403028", "Sprakensehl", null], - ["031515403029", "Steinhorst", null], - ["031515404006", "Calberlah", null], - ["031515404013", "Isenbüttel", null], - ["031515404022", "Ribbesbüttel", null], - ["031515404037", "Wasbüttel", null], - ["031515405012", "Hillerse", null], - ["031515405015", "Leiferde", null], - ["031515405017", "Meinersen", null], - ["031515405018", "Müden (Aller)", null], - ["031515406001", "Adenbüttel", null], - ["031515406016", "Meine", null], - ["031515406023", "Rötgesbüttel", null], - ["031515406027", "Schwülper", null], - ["031515406034", "Vordorf", null], - ["031515406041", "Didderse", null], - ["031515407010", "Groß Oesingen", null], - ["031515407026", "Schönewörde", null], - ["031515407033", "Ummern", null], - ["031515407035", "Wagenhoff", null], - ["031515407036", "Wahrenholz", null], - ["031515407038", "Wesendorf", null], - ["031519501501", "Giebel, gemfr. Gebiet", null], - ["031530002002", "Bad Harzburg, Stadt", null], - ["031530007007", "Langelsheim, Stadt", null], - ["031530008008", "Liebenburg", null], - ["031530012012", "Seesen, Stadt", null], - ["031530016016", "Braunlage, Stadt", null], - ["031530017017", "Goslar, Stadt", null], - ["031530018018", "Clausthal-Zellerfeld, Berg- und Universitätsstadt", null], - ["031535401006", "Hahausen", null], - ["031535401009", "Lutter am Barenberge, Flecken", null], - ["031535401014", "Wallmoden", null], - ["031539504504", "Harz (Landkreis Goslar), gemfr. Gebiet", null], - ["031540013013", "Königslutter am Elm, Stadt", null], - ["031540014014", "Lehre", null], - ["031540019019", "Schöningen, Stadt", null], - ["031540028028", "Helmstedt, Stadt", null], - ["031545401008", "Grasleben", null], - ["031545401015", "Mariental", null], - ["031545401016", "Querenhorst", null], - ["031545401018", "Rennau", null], - ["031545402002", "Beierstedt", null], - ["031545402006", "Gevensleben", null], - ["031545402012", "Jerxheim", null], - ["031545402027", "Söllingen", null], - ["031545403005", "Frellstedt", null], - ["031545403017", "Räbke", null], - ["031545403021", "Süpplingen", null], - ["031545403022", "Süpplingenburg", null], - ["031545403025", "Warberg", null], - ["031545403026", "Wolsdorf", null], - ["031545404001", "Bahrdorf", null], - ["031545404004", "Danndorf", null], - ["031545404007", "Grafhorst", null], - ["031545404009", "Groß Twülpstedt", null], - ["031545404024", "Velpke", null], - ["031549501501", "Brunsleberfeld, gemfr. Gebiet", null], - ["031549502502", "Helmstedt, gemfr. Gebiet", null], - ["031549503503", "Königslutter, gemfr. Gebiet", null], - ["031549504504", "Mariental, gemfr. Gebiet", null], - ["031549506506", "Schöningen, gemfr. Gebiet", null], - ["031550001001", "Bad Gandersheim, Stadt", null], - ["031550002002", "Bodenfelde, Flecken", null], - ["031550003003", "Dassel, Stadt", null], - ["031550005005", "Hardegsen, Stadt", null], - ["031550006006", "Kalefeld", null], - ["031550007007", "Katlenburg-Lindau", null], - ["031550009009", "Moringen, Stadt", null], - ["031550010010", "Nörten-Hardenberg, Flecken", null], - ["031550011011", "Northeim, Stadt", null], - ["031550012012", "Uslar, Stadt", null], - ["031550013013", "Einbeck, Stadt", null], - ["031559501501", "Solling (Landkreis Northeim), gemfr. Geb.", null], - ["031570001001", "Edemissen", null], - ["031570002002", "Hohenhameln", null], - ["031570005005", "Lengede", null], - ["031570006006", "Peine, Stadt", null], - ["031570007007", "Vechelde", null], - ["031570008008", "Wendeburg", null], - ["031570009009", "Ilsede", null], - ["031580006006", "Cremlingen", null], - ["031580037037", "Wolfenbüttel, Stadt", null], - ["031580039039", "Schladen-Werla", null], - ["031585402002", "Baddeckenstedt", null], - ["031585402004", "Burgdorf", null], - ["031585402011", "Elbe", null], - ["031585402016", "Haverlah", null], - ["031585402018", "Heere", null], - ["031585402028", "Sehlde", null], - ["031585403005", "Cramme", null], - ["031585403010", "Dorstadt", null], - ["031585403014", "Flöthe", null], - ["031585403019", "Heiningen", null], - ["031585403023", "Ohrum", null], - ["031585403038", "Börßum", null], - ["031585406009", "Dettum", null], - ["031585406012", "Erkerode", null], - ["031585406013", "Evessen", null], - ["031585406030", "Sickte", null], - ["031585406033", "Veltheim (Ohe)", null], - ["031585407007", "Dahlum", null], - ["031585407008", "Denkte", null], - ["031585407017", "Hedeper", null], - ["031585407021", "Kissenbrück", null], - ["031585407022", "Kneitlingen", null], - ["031585407025", "Roklum", null], - ["031585407027", "Schöppenstedt, Stadt", null], - ["031585407031", "Uehrde", null], - ["031585407032", "Vahlberg", null], - ["031585407035", "Winnigstedt", null], - ["031585407036", "Wittmar", null], - ["031585407040", "Remlingen-Semmenstedt", null], - ["031589501501", "Am Großen Rhode, gemfr. Gebiet", null], - ["031589502502", "Barnstorf-Warle, gemfr. Gebiet", null], - ["031589503503", "Voigtsdahlum, gemfr. Gebiet", null], - ["031590001001", "Adelebsen, Flecken", null], - ["031590002002", "Bad Grund (Harz)", null], - ["031590003003", "Bad Lauterberg im Harz, Stadt", null], - ["031590004004", "Bad Sachsa, Stadt", null], - ["031590007007", "Bovenden, Flecken", null], - ["031590010010", "Duderstadt, Stadt", null], - ["031590013013", "Friedland", null], - ["031590015015", "Gleichen", null], - ["031590016016", "Göttingen, Stadt", null], - ["031590017017", "Hann. Münden, Stadt", null], - ["031590019019", "Herzberg am Harz, Stadt", null], - ["031590026026", "Osterode am Harz, Stadt", null], - ["031590029029", "Rosdorf", null], - ["031590034034", "Staufenberg", null], - ["031590036036", "Walkenried", null], - ["031595401008", "Bühren", null], - ["031595401009", "Dransfeld, Stadt", null], - ["031595401021", "Jühnde", null], - ["031595401024", "Niemetal", null], - ["031595401031", "Scheden", null], - ["031595402005", "Bilshausen", null], - ["031595402006", "Bodensee", null], - ["031595402014", "Gieboldehausen, Flecken", null], - ["031595402022", "Krebeck", null], - ["031595402025", "Obernfeld", null], - ["031595402027", "Rhumspringe", null], - ["031595402028", "Rollshausen", null], - ["031595402030", "Rüdershausen", null], - ["031595402037", "Wollbrandshausen", null], - ["031595402038", "Wollershausen", null], - ["031595403012", "Elbingerode", null], - ["031595403018", "Hattorf am Harz", null], - ["031595403020", "Hörden am Harz", null], - ["031595403039", "Wulften am Harz", null], - ["031595404011", "Ebergötzen", null], - ["031595404023", "Landolfshausen", null], - ["031595404032", "Seeburg", null], - ["031595404033", "Seulingen", null], - ["031595404035", "Waake", null], - ["031599501501", "Harz (Landkreis Göttingen), gemfr. Geb.", null], - ["032410001001", "Hannover, Landeshauptstadt", null], - ["032410002002", "Barsinghausen, Stadt", null], - ["032410003003", "Burgdorf, Stadt", null], - ["032410004004", "Burgwedel, Stadt", null], - ["032410005005", "Garbsen, Stadt", null], - ["032410006006", "Gehrden, Stadt", null], - ["032410007007", "Hemmingen, Stadt", null], - ["032410008008", "Isernhagen", null], - ["032410009009", "Laatzen, Stadt", null], - ["032410010010", "Langenhagen, Stadt", null], - ["032410011011", "Lehrte, Stadt", null], - ["032410012012", "Neustadt am Rübenberge, Stadt", null], - ["032410013013", "Pattensen, Stadt", null], - ["032410014014", "Ronnenberg, Stadt", null], - ["032410015015", "Seelze, Stadt", null], - ["032410016016", "Sehnde, Stadt", null], - ["032410017017", "Springe, Stadt", null], - ["032410018018", "Uetze", null], - ["032410019019", "Wedemark", null], - ["032410020020", "Wennigsen (Deister)", null], - ["032410021021", "Wunstorf, Stadt", null], - ["032510007007", "Bassum, Stadt", null], - ["032510012012", "Diepholz, Stadt", null], - ["032510037037", "Stuhr", null], - ["032510040040", "Sulingen, Stadt", null], - ["032510041041", "Syke, Stadt", null], - ["032510042042", "Twistringen, Stadt", null], - ["032510044044", "Wagenfeld", null], - ["032510047047", "Weyhe", null], - ["032515401009", "Brockum", null], - ["032515401020", "Hüde", null], - ["032515401022", "Lembruch", null], - ["032515401023", "Lemförde, Flecken", null], - ["032515401025", "Marl", null], - ["032515401029", "Quernheim", null], - ["032515401036", "Stemshorn", null], - ["032515402005", "Barnstorf, Flecken", null], - ["032515402013", "Drebber", null], - ["032515402014", "Drentwede", null], - ["032515402017", "Eydelstedt", null], - ["032515403002", "Asendorf", null], - ["032515403026", "Martfeld", null], - ["032515403033", "Schwarme", null], - ["032515403049", "Bruchhausen-Vilsen, Flecken", null], - ["032515404003", "Bahrenborstel", null], - ["032515404004", "Barenburg, Flecken", null], - ["032515404018", "Freistatt", null], - ["032515404021", "Kirchdorf", null], - ["032515404043", "Varrel", null], - ["032515404045", "Wehrbleck", null], - ["032515405006", "Barver", null], - ["032515405011", "Dickel", null], - ["032515405019", "Hemsloh", null], - ["032515405030", "Rehden", null], - ["032515405046", "Wetschen", null], - ["032515406001", "Affinghausen", null], - ["032515406015", "Ehrenburg", null], - ["032515406028", "Neuenkirchen", null], - ["032515406031", "Scholen", null], - ["032515406032", "Schwaförden", null], - ["032515406038", "Sudwalde", null], - ["032515407008", "Borstel", null], - ["032515407024", "Maasen", null], - ["032515407027", "Mellinghausen", null], - ["032515407034", "Siedenburg, Flecken", null], - ["032515407035", "Staffhorst", null], - ["032520001001", "Aerzen, Flecken", null], - ["032520002002", "Bad Münder am Deister, Stadt", null], - ["032520003003", "Bad Pyrmont, Stadt", null], - ["032520004004", "Coppenbrügge, Flecken", null], - ["032520005005", "Emmerthal", null], - ["032520006006", "Hameln, Stadt", null], - ["032520007007", "Hessisch Oldendorf, Stadt", null], - ["032520008008", "Salzhemmendorf, Flecken", null], - ["032540002002", "Alfeld (Leine), Stadt", null], - ["032540003003", "Algermissen", null], - ["032540005005", "Bad Salzdetfurth, Stadt", null], - ["032540008008", "Bockenem, Stadt", null], - ["032540011011", "Diekholzen", null], - ["032540014014", "Elze, Stadt", null], - ["032540017017", "Giesen", null], - ["032540020020", "Harsum", null], - ["032540021021", "Hildesheim, Stadt", null], - ["032540022022", "Holle", null], - ["032540026026", "Nordstemmen", null], - ["032540028028", "Sarstedt, Stadt", null], - ["032540029029", "Schellerten", null], - ["032540032032", "Söhlde", null], - ["032540042042", "Freden (Leine)", null], - ["032540044044", "Lamspringe", null], - ["032540045045", "Sibbesse", null], - ["032545406013", "Eime, Flecken", null], - ["032545406041", "Duingen, Flecken", null], - ["032545406043", "Gronau (Leine), Stadt", null], - ["032550008008", "Delligsen, Flecken", null], - ["032550023023", "Holzminden, Stadt", null], - ["032555401002", "Bevern, Flecken", null], - ["032555401015", "Golmbach", null], - ["032555401021", "Holenberg", null], - ["032555401030", "Negenborn", null], - ["032555403004", "Boffzen", null], - ["032555403009", "Derental", null], - ["032555403014", "Fürstenberg", null], - ["032555403026", "Lauenförde, Flecken", null], - ["032555408003", "Bodenwerder, Münchhausenstadt", null], - ["032555408005", "Brevörde", null], - ["032555408016", "Halle", null], - ["032555408017", "Hehlen", null], - ["032555408019", "Heinsen", null], - ["032555408020", "Heyen", null], - ["032555408025", "Kirchbrak", null], - ["032555408031", "Ottenstein, Flecken", null], - ["032555408032", "Pegestorf", null], - ["032555408033", "Polle, Flecken", null], - ["032555408035", "Vahlbruch", null], - ["032555409001", "Arholzen", null], - ["032555409007", "Deensen", null], - ["032555409010", "Dielmissen", null], - ["032555409012", "Eimen", null], - ["032555409013", "Eschershausen, Stadt", null], - ["032555409018", "Heinade", null], - ["032555409022", "Holzen", null], - ["032555409027", "Lenne", null], - ["032555409028", "Lüerdissen", null], - ["032555409034", "Stadtoldendorf, Stadt", null], - ["032555409036", "Wangelnstedt", null], - ["032559501501", "Boffzen, gemfr. Gebiet", null], - ["032559502502", "Eimen, gemfr. Gebiet", null], - ["032559503503", "Eschershausen, gemfr. Gebiet", null], - ["032559504504", "Grünenplan, gemfr. Gebiet", null], - ["032559505505", "Holzminden, gemfr. Gebiet", null], - ["032559506506", "Merxhausen, gemfr. Gebiet", null], - ["032559508508", "Wenzen, gemfr. Gebiet", null], - ["032560022022", "Nienburg (Weser), Stadt", null], - ["032560025025", "Rehburg-Loccum, Stadt", null], - ["032560030030", "Steyerberg, Flecken", null], - ["032565402005", "Drakenburg, Flecken", null], - ["032565402011", "Haßbergen", null], - ["032565402012", "Heemsen", null], - ["032565402027", "Rohrsen", null], - ["032565405002", "Binnen", null], - ["032565405019", "Liebenau, Flecken", null], - ["032565405023", "Pennigsehl", null], - ["032565406001", "Balge", null], - ["032565406021", "Marklohe", null], - ["032565406036", "Wietzen", null], - ["032565407020", "Linsburg", null], - ["032565407026", "Rodewald", null], - ["032565407029", "Steimbke", null], - ["032565407031", "Stöckse", null], - ["032565408004", "Diepenau, Flecken", null], - ["032565408024", "Raddestorf", null], - ["032565408033", "Uchte, Flecken", null], - ["032565408034", "Warmsen", null], - ["032565409003", "Bücken, Flecken", null], - ["032565409007", "Eystrup", null], - ["032565409008", "Gandesbergen", null], - ["032565409009", "Hämelhausen", null], - ["032565409010", "Hassel (Weser)", null], - ["032565409013", "Hilgermissen", null], - ["032565409014", "Hoya, Stadt", null], - ["032565409015", "Hoyerhagen", null], - ["032565409028", "Schweringen", null], - ["032565409035", "Warpe", null], - ["032565410006", "Estorf", null], - ["032565410016", "Husum", null], - ["032565410017", "Landesbergen", null], - ["032565410018", "Leese", null], - ["032565410032", "Stolzenau", null], - ["032570003003", "Auetal", null], - ["032570009009", "Bückeburg, Stadt", null], - ["032570028028", "Obernkirchen, Stadt", null], - ["032570031031", "Rinteln, Stadt", null], - ["032570035035", "Stadthagen, Stadt", null], - ["032575401001", "Ahnsen", null], - ["032575401005", "Bad Eilsen", null], - ["032575401008", "Buchholz", null], - ["032575401012", "Heeßen", null], - ["032575401022", "Luhden", null], - ["032575402007", "Beckedorf", null], - ["032575402015", "Heuerßen", null], - ["032575402020", "Lindhorst", null], - ["032575402021", "Lüdersfeld", null], - ["032575403006", "Bad Nenndorf, Stadt", null], - ["032575403011", "Haste", null], - ["032575403016", "Hohnhorst", null], - ["032575403036", "Suthfeld", null], - ["032575404019", "Lauenhagen", null], - ["032575404023", "Meerbeck", null], - ["032575404025", "Niedernwöhren", null], - ["032575404027", "Nordsehl", null], - ["032575404030", "Pollhagen", null], - ["032575404037", "Wiedensahl, Flecken", null], - ["032575405013", "Helpsen", null], - ["032575405014", "Hespe", null], - ["032575405026", "Nienstädt", null], - ["032575405034", "Seggebruch", null], - ["032575406002", "Apelern", null], - ["032575406017", "Hülsede", null], - ["032575406018", "Lauenau, Flecken", null], - ["032575406024", "Messenkamp", null], - ["032575406029", "Pohle", null], - ["032575406032", "Rodenberg, Stadt", null], - ["032575407004", "Auhagen", null], - ["032575407010", "Hagenburg, Flecken", null], - ["032575407033", "Sachsenhagen, Stadt", null], - ["032575407038", "Wölpinghausen", null], - ["033510004004", "Bergen, Stadt", null], - ["033510006006", "Celle, Stadt", null], - ["033510010010", "Faßberg", null], - ["033510012012", "Hambühren", null], - ["033510023023", "Wietze", null], - ["033510024024", "Winsen (Aller)", null], - ["033510025025", "Eschede", null], - ["033510026026", "Südheide", null], - ["033515402005", "Bröckel", null], - ["033515402007", "Eicklingen", null], - ["033515402017", "Langlingen", null], - ["033515402022", "Wienhausen, Klostergemeinde", null], - ["033515403002", "Ahnsbeck", null], - ["033515403003", "Beedenbostel", null], - ["033515403008", "Eldingen", null], - ["033515403015", "Hohne", null], - ["033515403016", "Lachendorf", null], - ["033515404001", "Adelheidsdorf", null], - ["033515404018", "Nienhagen", null], - ["033515404021", "Wathlingen", null], - ["033519501501", "Lohheide, gemfr. Bezirk", null], - ["033520011011", "Cuxhaven, Stadt", null], - ["033520032032", "Loxstedt", null], - ["033520050050", "Schiffdorf", null], - ["033520059059", "Beverstedt", null], - ["033520060060", "Hagen im Bremischen", null], - ["033520061061", "Wurster Nordseeküste", null], - ["033520062062", "Geestland, Stadt", null], - ["033525404002", "Armstorf", null], - ["033525404024", "Hollnseth", null], - ["033525404029", "Lamstedt", null], - ["033525404036", "Mittelstenahe", null], - ["033525404052", "Stinstedt", null], - ["033525407020", "Hechthausen", null], - ["033525407022", "Hemmoor, Stadt", null], - ["033525407044", "Osten", null], - ["033525411004", "Belum", null], - ["033525411008", "Bülkau", null], - ["033525411025", "Ihlienworth", null], - ["033525411038", "Neuenkirchen", null], - ["033525411039", "Neuhaus (Oste), Flecken", null], - ["033525411041", "Nordleda", null], - ["033525411042", "Oberndorf", null], - ["033525411043", "Odisheim", null], - ["033525411045", "Osterbruch", null], - ["033525411046", "Otterndorf, Stadt", null], - ["033525411051", "Steinau", null], - ["033525411055", "Wanna", null], - ["033525411056", "Wingst", null], - ["033525411063", "Cadenberge", null], - ["033530005005", "Buchholz in der Nordheide, Stadt", null], - ["033530026026", "Neu Wulmstorf", null], - ["033530029029", "Rosengarten", null], - ["033530031031", "Seevetal", null], - ["033530032032", "Stelle", null], - ["033530040040", "Winsen (Luhe), Stadt", null], - ["033535401007", "Drage", null], - ["033535401023", "Marschacht", null], - ["033535401033", "Tespe", null], - ["033535402002", "Asendorf", null], - ["033535402004", "Brackel", null], - ["033535402009", "Egestorf", null], - ["033535402016", "Hanstedt", null], - ["033535402024", "Marxen", null], - ["033535402036", "Undeloh", null], - ["033535403001", "Appel", null], - ["033535403008", "Drestedt", null], - ["033535403014", "Halvesbostel", null], - ["033535403019", "Hollenstedt", null], - ["033535403025", "Moisburg", null], - ["033535403028", "Regesbostel", null], - ["033535403039", "Wenzendorf", null], - ["033535404003", "Bendestorf", null], - ["033535404017", "Harmstorf", null], - ["033535404020", "Jesteburg", null], - ["033535405010", "Eyendorf", null], - ["033535405011", "Garlstorf", null], - ["033535405012", "Garstedt", null], - ["033535405013", "Gödenstorf", null], - ["033535405030", "Salzhausen", null], - ["033535405034", "Toppenstedt", null], - ["033535405037", "Vierhöfen", null], - ["033535405042", "Wulfsen", null], - ["033535406006", "Dohren", null], - ["033535406015", "Handeloh", null], - ["033535406018", "Heidenau", null], - ["033535406021", "Kakenstorf", null], - ["033535406022", "Königsmoor", null], - ["033535406027", "Otter", null], - ["033535406035", "Tostedt", null], - ["033535406038", "Welle", null], - ["033535406041", "Wistedt", null], - ["033545403005", "Gartow, Flecken", null], - ["033545403007", "Gorleben", null], - ["033545403010", "Höhbeck", null], - ["033545403020", "Prezelle", null], - ["033545403021", "Schnackenburg, Stadt", null], - ["033545406003", "Damnatz", null], - ["033545406004", "Dannenberg (Elbe), Stadt", null], - ["033545406006", "Göhrde", null], - ["033545406008", "Gusborn", null], - ["033545406009", "Hitzacker (Elbe), Stadt", null], - ["033545406011", "Jameln", null], - ["033545406012", "Karwitz", null], - ["033545406014", "Langendorf", null], - ["033545406019", "Neu Darchau", null], - ["033545406027", "Zernien", null], - ["033545407001", "Bergen an der Dumme, Flecken", null], - ["033545407002", "Clenze, Flecken", null], - ["033545407013", "Küsten", null], - ["033545407015", "Lemgow", null], - ["033545407016", "Luckau (Wendland)", null], - ["033545407017", "Lübbow", null], - ["033545407018", "Lüchow (Wendland), Stadt", null], - ["033545407022", "Schnega", null], - ["033545407023", "Trebel", null], - ["033545407024", "Waddeweitz", null], - ["033545407025", "Woltersdorf", null], - ["033545407026", "Wustrow (Wendland), Stadt", null], - ["033549501501", "Gartow, gemfr. Gebiet", null], - ["033549502502", "Göhrde, gemfr. Gebiet", null], - ["033550001001", "Adendorf", null], - ["033550009009", "Bleckede, Stadt", null], - ["033550022022", "Lüneburg, Hansestadt", null], - ["033550049049", "Amt Neuhaus", null], - ["033555401002", "Amelinghausen", null], - ["033555401008", "Betzendorf", null], - ["033555401027", "Oldendorf (Luhe)", null], - ["033555401029", "Rehlingen", null], - ["033555401034", "Soderstorf", null], - ["033555402004", "Bardowick, Flecken", null], - ["033555402007", "Barum", null], - ["033555402017", "Handorf", null], - ["033555402023", "Mechtersen", null], - ["033555402028", "Radbruch", null], - ["033555402039", "Vögelsen", null], - ["033555402042", "Wittorf", null], - ["033555403010", "Boitze", null], - ["033555403012", "Dahlem", null], - ["033555403013", "Dahlenburg, Flecken", null], - ["033555403025", "Nahrendorf", null], - ["033555403037", "Tosterglope", null], - ["033555404020", "Kirchgellersen", null], - ["033555404031", "Reppenstedt", null], - ["033555404035", "Südergellersen", null], - ["033555404041", "Westergellersen", null], - ["033555405006", "Barnstedt", null], - ["033555405014", "Deutsch Evern", null], - ["033555405016", "Embsen", null], - ["033555405024", "Melbeck", null], - ["033555406005", "Barendorf", null], - ["033555406026", "Neetze", null], - ["033555406030", "Reinstorf", null], - ["033555406036", "Thomasburg", null], - ["033555406038", "Vastorf", null], - ["033555406040", "Wendisch Evern", null], - ["033555407003", "Artlenburg, Flecken", null], - ["033555407011", "Brietlingen", null], - ["033555407015", "Echem", null], - ["033555407018", "Hittbergen", null], - ["033555407019", "Hohnstorf (Elbe)", null], - ["033555407021", "Lüdersburg", null], - ["033555407032", "Rullstorf", null], - ["033555407033", "Scharnebeck", null], - ["033560002002", "Grasberg", null], - ["033560005005", "Lilienthal", null], - ["033560007007", "Osterholz-Scharmbeck, Stadt", null], - ["033560008008", "Ritterhude", null], - ["033560009009", "Schwanewede", null], - ["033560011011", "Worpswede", null], - ["033565401001", "Axstedt", null], - ["033565401003", "Hambergen", null], - ["033565401004", "Holste", null], - ["033565401006", "Lübberstedt", null], - ["033565401010", "Vollersode", null], - ["033570008008", "Bremervörde, Stadt", null], - ["033570016016", "Gnarrenburg", null], - ["033570039039", "Rotenburg (Wümme), Stadt", null], - ["033570041041", "Scheeßel", null], - ["033570051051", "Visselhövede, Stadt", null], - ["033575401006", "Bothel", null], - ["033575401009", "Brockel", null], - ["033575401024", "Hemsbünde", null], - ["033575401025", "Hemslingen", null], - ["033575401031", "Kirchwalsede", null], - ["033575401054", "Westerwalsede", null], - ["033575402015", "Fintel", null], - ["033575402023", "Helvesiek", null], - ["033575402033", "Lauenbrück", null], - ["033575402046", "Stemmen", null], - ["033575402049", "Vahlde", null], - ["033575403002", "Alfstedt", null], - ["033575403004", "Basdahl", null], - ["033575403012", "Ebersdorf", null], - ["033575403027", "Hipstedt", null], - ["033575403035", "Oerel", null], - ["033575404003", "Anderlingen", null], - ["033575404011", "Deinstedt", null], - ["033575404014", "Farven", null], - ["033575404036", "Ostereistedt", null], - ["033575404038", "Rhade", null], - ["033575404040", "Sandbostel", null], - ["033575404042", "Seedorf", null], - ["033575404043", "Selsingen", null], - ["033575405017", "Groß Meckelsen", null], - ["033575405019", "Hamersen", null], - ["033575405029", "Kalbe", null], - ["033575405032", "Klein Meckelsen", null], - ["033575405034", "Lengenbostel", null], - ["033575405044", "Sittensen", null], - ["033575405048", "Tiste", null], - ["033575405050", "Vierden", null], - ["033575405056", "Wohnste", null], - ["033575406001", "Ahausen", null], - ["033575406005", "Bötersen", null], - ["033575406020", "Hassendorf", null], - ["033575406022", "Hellwege", null], - ["033575406028", "Horstedt", null], - ["033575406037", "Reeßum", null], - ["033575406045", "Sottrum", null], - ["033575407007", "Breddorf", null], - ["033575407010", "Bülstedt", null], - ["033575407026", "Hepstedt", null], - ["033575407030", "Kirchtimke", null], - ["033575407047", "Tarmstedt", null], - ["033575407052", "Vorwerk", null], - ["033575407053", "Westertimke", null], - ["033575407055", "Wilstedt", null], - ["033575408013", "Elsdorf", null], - ["033575408018", "Gyhum", null], - ["033575408021", "Heeslingen", null], - ["033575408057", "Zeven, Stadt", null], - ["033580002002", "Bispingen", null], - ["033580008008", "Bad Fallingbostel, Stadt", null], - ["033580016016", "Munster, Stadt", null], - ["033580017017", "Neuenkirchen", null], - ["033580019019", "Schneverdingen, Stadt", null], - ["033580021021", "Soltau, Stadt", null], - ["033580023023", "Wietzendorf", null], - ["033580024024", "Walsrode, Stadt", null], - ["033585401001", "Ahlden (Aller), Flecken", null], - ["033585401006", "Eickeloh", null], - ["033585401011", "Grethem", null], - ["033585401012", "Hademstorf", null], - ["033585401014", "Hodenhagen", null], - ["033585402003", "Böhme", null], - ["033585402009", "Frankenfeld", null], - ["033585402013", "Häuslingen", null], - ["033585402018", "Rethem (Aller), Stadt", null], - ["033585403005", "Buchholz (Aller)", null], - ["033585403007", "Essel", null], - ["033585403010", "Gilten", null], - ["033585403015", "Lindwedel", null], - ["033585403020", "Schwarmstedt", null], - ["033589501501", "Osterheide, gemfr. Bezirk", null], - ["033590010010", "Buxtehude, Hansestadt", null], - ["033590013013", "Drochtersen", null], - ["033590028028", "Jork", null], - ["033590038038", "Stade, Hansestadt", null], - ["033595401003", "Apensen", null], - ["033595401006", "Beckdorf", null], - ["033595401037", "Sauensiek", null], - ["033595402011", "Deinste", null], - ["033595402017", "Fredenbeck", null], - ["033595402031", "Kutenholz", null], - ["033595403002", "Ahlerstedt", null], - ["033595403005", "Bargstedt", null], - ["033595403008", "Brest", null], - ["033595403023", "Harsefeld, Flecken", null], - ["033595405001", "Agathenburg", null], - ["033595405007", "Bliedersdorf", null], - ["033595405012", "Dollern", null], - ["033595405027", "Horneburg, Flecken", null], - ["033595405034", "Nottensdorf", null], - ["033595406020", "Grünendeich", null], - ["033595406021", "Guderhandviertel", null], - ["033595406026", "Hollern-Twielenfleth", null], - ["033595406032", "Mittelnkirchen", null], - ["033595406033", "Neuenkirchen", null], - ["033595406039", "Steinkirchen", null], - ["033595407004", "Balje", null], - ["033595407018", "Freiburg (Elbe), Flecken", null], - ["033595407030", "Krummendeich", null], - ["033595407035", "Oederquart", null], - ["033595407040", "Wischhafen", null], - ["033595409009", "Burweg", null], - ["033595409014", "Düdenbüttel", null], - ["033595409015", "Engelschoff", null], - ["033595409016", "Estorf", null], - ["033595409019", "Großenwörden", null], - ["033595409022", "Hammah", null], - ["033595409024", "Heinbockel", null], - ["033595409025", "Himmelpforten", null], - ["033595409029", "Kranenburg", null], - ["033595409036", "Oldendorf", null], - ["033600004004", "Bienenbüttel", null], - ["033600025025", "Uelzen, Hansestadt", null], - ["033605404015", "Oetzen", null], - ["033605404016", "Rätzlingen", null], - ["033605404018", "Rosche", null], - ["033605404022", "Stoetze", null], - ["033605404024", "Suhlendorf", null], - ["033605405007", "Eimke", null], - ["033605405009", "Gerdau", null], - ["033605405023", "Suderburg", null], - ["033605407001", "Altenmedingen", null], - ["033605407002", "Bad Bevensen, Stadt", null], - ["033605407003", "Barum", null], - ["033605407006", "Ebstorf,Klosterflecken", null], - ["033605407008", "Emmendorf", null], - ["033605407010", "Hanstedt", null], - ["033605407011", "Himbergen", null], - ["033605407012", "Jelmstorf", null], - ["033605407014", "Natendorf", null], - ["033605407017", "Römstedt", null], - ["033605407019", "Schwienau", null], - ["033605407026", "Weste", null], - ["033605407029", "Wriedel", null], - ["033605408005", "Bad Bodenteich, Flecken", null], - ["033605408013", "Lüder", null], - ["033605408020", "Soltendieck", null], - ["033605408030", "Wrestedt", null], - ["033610001001", "Achim, Stadt", null], - ["033610003003", "Dörverden", null], - ["033610005005", "Kirchlinteln", null], - ["033610006006", "Langwedel, Flecken", null], - ["033610008008", "Ottersberg, Flecken", null], - ["033610009009", "Oyten", null], - ["033610012012", "Verden (Aller), Stadt", null], - ["033615401002", "Blender", null], - ["033615401004", "Emtinghausen", null], - ["033615401010", "Riede", null], - ["033615401013", "Thedinghausen", null], - ["034010000000", "Delmenhorst, Stadt", null], - ["034020000000", "Emden, Stadt", null], - ["034030000000", "Oldenburg (Oldenburg), Stadt", null], - ["034040000000", "Osnabrück, Stadt", null], - ["034050000000", "Wilhelmshaven, Stadt", null], - ["034510001001", "Apen", null], - ["034510002002", "Bad Zwischenahn", null], - ["034510004004", "Edewecht", null], - ["034510005005", "Rastede", null], - ["034510007007", "Westerstede, Stadt", null], - ["034510008008", "Wiefelstede", null], - ["034520001001", "Aurich, Stadt", null], - ["034520002002", "Baltrum", null], - ["034520006006", "Großefehn", null], - ["034520007007", "Großheide", null], - ["034520011011", "Hinte", null], - ["034520012012", "Ihlow", null], - ["034520013013", "Juist, Inselgemeinde", null], - ["034520014014", "Krummhörn", null], - ["034520019019", "Norden, Stadt", null], - ["034520020020", "Norderney, Stadt", null], - ["034520023023", "Südbrookmerland", null], - ["034520025025", "Wiesmoor, Stadt", null], - ["034520027027", "Dornum", null], - ["034525401015", "Leezdorf", null], - ["034525401017", "Marienhafe, Flecken", null], - ["034525401021", "Osteel", null], - ["034525401022", "Rechtsupweg", null], - ["034525401024", "Upgant-Schott", null], - ["034525401026", "Wirdum", null], - ["034525403003", "Berumbur", null], - ["034525403008", "Hage, Flecken", null], - ["034525403009", "Hagermarsch", null], - ["034525403010", "Halbemond", null], - ["034525403016", "Lütetsburg", null], - ["034529501501", "Nordseeinsel Memmert, gemfr. Gebiet", null], - ["034530001001", "Barßel", null], - ["034530002002", "Bösel", null], - ["034530003003", "Cappeln (Oldenburg)", null], - ["034530004004", "Cloppenburg, Stadt", null], - ["034530005005", "Emstek", null], - ["034530006006", "Essen (Oldenburg)", null], - ["034530007007", "Friesoythe, Stadt", null], - ["034530008008", "Garrel", null], - ["034530009009", "Lastrup", null], - ["034530010010", "Lindern (Oldenburg)", null], - ["034530011011", "Löningen, Stadt", null], - ["034530012012", "Molbergen", null], - ["034530013013", "Saterland", null], - ["034540010010", "Emsbüren", null], - ["034540014014", "Geeste", null], - ["034540018018", "Haren (Ems), Stadt", null], - ["034540019019", "Haselünne, Stadt", null], - ["034540032032", "Lingen (Ems), Stadt", null], - ["034540035035", "Meppen, Stadt", null], - ["034540041041", "Papenburg, Stadt", null], - ["034540044044", "Rhede (Ems)", null], - ["034540045045", "Salzbergen", null], - ["034540054054", "Twist", null], - ["034545401007", "Dersum", null], - ["034545401008", "Dörpen", null], - ["034545401020", "Heede", null], - ["034545401025", "Kluse", null], - ["034545401030", "Lehe", null], - ["034545401037", "Neubörger", null], - ["034545401038", "Neulehe", null], - ["034545401056", "Walchum", null], - ["034545401060", "Wippingen", null], - ["034545402001", "Andervenne", null], - ["034545402003", "Beesten", null], - ["034545402012", "Freren, Stadt", null], - ["034545402036", "Messingen", null], - ["034545402053", "Thuine", null], - ["034545403009", "Dohren", null], - ["034545403021", "Herzlake", null], - ["034545403026", "Lähden", null], - ["034545404013", "Fresenburg", null], - ["034545404029", "Lathen", null], - ["034545404039", "Niederlangen", null], - ["034545404040", "Oberlangen", null], - ["034545404043", "Renkenberge", null], - ["034545404052", "Sustrum", null], - ["034545405002", "Bawinkel", null], - ["034545405015", "Gersten", null], - ["034545405017", "Handrup", null], - ["034545405028", "Langen", null], - ["034545405031", "Lengerich", null], - ["034545405059", "Wettrup", null], - ["034545406004", "Bockhorst", null], - ["034545406006", "Breddenberg", null], - ["034545406011", "Esterwegen", null], - ["034545406022", "Hilkenbrook", null], - ["034545406051", "Surwold", null], - ["034545407005", "Börger", null], - ["034545407016", "Groß Berßen", null], - ["034545407023", "Hüven", null], - ["034545407024", "Klein Berßen", null], - ["034545407047", "Sögel", null], - ["034545407048", "Spahnharrenstätte", null], - ["034545407050", "Stavern", null], - ["034545407058", "Werpeloh", null], - ["034545408034", "Lünne", null], - ["034545408046", "Schapen", null], - ["034545408049", "Spelle", null], - ["034545409027", "Lahn", null], - ["034545409033", "Lorup", null], - ["034545409042", "Rastdorf", null], - ["034545409055", "Vrees", null], - ["034545409057", "Werlte, Stadt", null], - ["034550007007", "Jever, Stadt", null], - ["034550014014", "Sande", null], - ["034550015015", "Schortens, Stadt", null], - ["034550020020", "Wangerland", null], - ["034550021021", "Wangerooge, Nordseebad", null], - ["034550025025", "Bockhorn", null], - ["034550026026", "Varel, Stadt", null], - ["034550027027", "Zetel", null], - ["034560001001", "Bad Bentheim, Stadt", null], - ["034560015015", "Nordhorn, Stadt", null], - ["034560025025", "Wietmarschen", null], - ["034565401002", "Emlichheim", null], - ["034565401009", "Hoogstede", null], - ["034565401012", "Laar", null], - ["034565401019", "Ringe", null], - ["034565402004", "Esche", null], - ["034565402005", "Georgsdorf", null], - ["034565402013", "Lage", null], - ["034565402014", "Neuenhaus, Stadt", null], - ["034565402017", "Osterwald", null], - ["034565403003", "Engden", null], - ["034565403010", "Isterberg", null], - ["034565403016", "Ohne", null], - ["034565403018", "Quendorf", null], - ["034565403020", "Samern", null], - ["034565403027", "Schüttorf, Stadt", null], - ["034565404006", "Getelo", null], - ["034565404007", "Gölenkamp", null], - ["034565404008", "Halle", null], - ["034565404011", "Itterbeck", null], - ["034565404023", "Uelsen", null], - ["034565404024", "Wielen", null], - ["034565404026", "Wilsum", null], - ["034570002002", "Borkum, Stadt", null], - ["034570012012", "Jemgum", null], - ["034570013013", "Leer (Ostfriesland), Stadt", null], - ["034570014014", "Moormerland", null], - ["034570017017", "Ostrhauderfehn", null], - ["034570018018", "Rhauderfehn", null], - ["034570020020", "Uplengen", null], - ["034570021021", "Weener, Stadt", null], - ["034570022022", "Westoverledingen", null], - ["034570024024", "Bunde", null], - ["034575402003", "Brinkum", null], - ["034575402009", "Firrel", null], - ["034575402010", "Hesel", null], - ["034575402011", "Holtland", null], - ["034575402015", "Neukamperfehn", null], - ["034575402019", "Schwerinsdorf", null], - ["034575403006", "Detern, Flecken", null], - ["034575403008", "Filsum", null], - ["034575403016", "Nortmoor", null], - ["034579501501", "Insel Lütje Hörn, gemfr. Gebiet", null], - ["034580003003", "Dötlingen", null], - ["034580005005", "Ganderkesee", null], - ["034580007007", "Großenkneten", null], - ["034580009009", "Hatten", null], - ["034580010010", "Hude (Oldb)", null], - ["034580013013", "Wardenburg", null], - ["034580014014", "Wildeshausen, Stadt", null], - ["034585401001", "Beckeln", null], - ["034585401002", "Colnrade", null], - ["034585401004", "Dünsen", null], - ["034585401006", "Groß Ippener", null], - ["034585401008", "Harpstedt, Flecken", null], - ["034585401011", "Kirchseelte", null], - ["034585401012", "Prinzhöfte", null], - ["034585401015", "Winkelsett", null], - ["034590003003", "Bad Essen", null], - ["034590004004", "Bad Iburg, Stadt", null], - ["034590005005", "Bad Laer", null], - ["034590006006", "Bad Rothenfelde", null], - ["034590008008", "Belm", null], - ["034590012012", "Bissendorf", null], - ["034590013013", "Bohmte", null], - ["034590014014", "Bramsche, Stadt", null], - ["034590015015", "Dissen am Teutoburger Wald, Stadt", null], - ["034590019019", "Georgsmarienhütte, Stadt", null], - ["034590020020", "Hagen am Teutoburger Wald", null], - ["034590021021", "Hasbergen", null], - ["034590022022", "Hilter am Teutoburger Wald", null], - ["034590024024", "Melle, Stadt", null], - ["034590029029", "Ostercappeln", null], - ["034590033033", "Wallenhorst", null], - ["034590034034", "Glandorf", null], - ["034595401007", "Badbergen", null], - ["034595401025", "Menslage", null], - ["034595401028", "Nortrup", null], - ["034595401030", "Quakenbrück, Stadt", null], - ["034595402001", "Alfhausen", null], - ["034595402002", "Ankum", null], - ["034595402010", "Bersenbrück, Stadt", null], - ["034595402016", "Eggermühlen", null], - ["034595402018", "Gehrde", null], - ["034595402023", "Kettenkamp", null], - ["034595402031", "Rieste", null], - ["034595403009", "Berge", null], - ["034595403011", "Bippen", null], - ["034595403017", "Fürstenau, Stadt", null], - ["034595404026", "Merzen", null], - ["034595404027", "Neuenkirchen", null], - ["034595404032", "Voltlage", null], - ["034600001001", "Bakum", null], - ["034600002002", "Damme, Stadt", null], - ["034600003003", "Dinklage, Stadt", null], - ["034600004004", "Goldenstedt", null], - ["034600005005", "Holdorf", null], - ["034600006006", "Lohne (Oldenburg), Stadt", null], - ["034600007007", "Neuenkirchen-Vörden", null], - ["034600008008", "Steinfeld (Oldenburg)", null], - ["034600009009", "Vechta, Stadt", null], - ["034600010010", "Visbek", null], - ["034610001001", "Berne", null], - ["034610002002", "Brake (Unterweser), Stadt", null], - ["034610003003", "Butjadingen", null], - ["034610004004", "Elsfleth, Stadt", null], - ["034610005005", "Jade", null], - ["034610006006", "Lemwerder", null], - ["034610007007", "Nordenham, Stadt", null], - ["034610008008", "Ovelgönne", null], - ["034610009009", "Stadland", null], - ["034620005005", "Friedeburg", null], - ["034620007007", "Langeoog", null], - ["034620014014", "Spiekeroog", null], - ["034620019019", "Wittmund, Stadt", null], - ["034625401002", "Dunum", null], - ["034625401003", "Esens, Stadt", null], - ["034625401006", "Holtgast", null], - ["034625401008", "Moorweg", null], - ["034625401010", "Neuharlingersiel", null], - ["034625401015", "Stedesdorf", null], - ["034625401017", "Werdum", null], - ["034625402001", "Blomberg", null], - ["034625402004", "Eversmeer", null], - ["034625402009", "Nenndorf", null], - ["034625402011", "Neuschoo", null], - ["034625402012", "Ochtersum", null], - ["034625402013", "Schweindorf", null], - ["034625402016", "Utarp", null], - ["034625402018", "Westerholt", null], - ["039019999999", "Nds-Küstengewässer(Gemarkung Nordsee)", null], - ["040110000000", "Bremen, Stadt", null], - ["040110111111", "Altstadt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110112112", "Bahnhofsvorstadt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110113113", "Ostertor", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110122122", "Industriehäfen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "040110123123", - "Stadtbremisches Überseehafengebiet Bremerhaven", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["040110124124", "Neustädter Hafen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110125125", "Hohentorshafen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110211211", "Alte Neustadt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110212212", "Hohentor", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110213213", "Neustadt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110214214", "Südervorstadt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110215215", "Gartenstadt Süd", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110216216", "Buntentor", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110217217", "Neuenland", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110218218", "Huckelriede", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110231231", "Habenhausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110232232", "Arsten", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110233233", "Kattenturm", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110234234", "Kattenesch", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110241241", "Mittelshuchting", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110242242", "Sodenmatt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110243243", "Kirchhuchting", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110244244", "Grolland", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110251251", "Woltmershausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110252252", "Rablinghausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110261261", "Seehausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110271271", "Strom", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110311311", "Steintor", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110312312", "Fesenfeld", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110313313", "Peterswerder", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110314314", "Hulsberg", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110321321", "Neu-Schwachhausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110322322", "Bürgerpark", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110323323", "Barkhof", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110324324", "Riensberg", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110325325", "Radio Bremen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110326326", "Schwachhausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110327327", "Gete", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110331331", "Gartenstadt Vahr", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110332332", "Neue Vahr Nord", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110334334", "Neue Vahr Südwest", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110335335", "Neue Vahr Südost", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110341341", "Horn", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110342342", "Lehe", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110343343", "Lehesterdeich", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110351351", "Borgfeld", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110361361", "Oberneuland", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110371371", "Ellener Feld", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "040110372372", - "Ellenerbrok-Schevemoor", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["040110373373", "Tenever", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110374374", "Osterholz", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110375375", "Blockdiek", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110381381", "Sebaldsbrück", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110382382", "Hastedt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110383383", "Hemelingen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110384384", "Arbergen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110385385", "Mahndorf", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110411411", "Blockland", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110421421", "Regensburger Straße", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "040110422422", - "Findorff-Bürgerweide", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["040110423423", "Weidedamm", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110424424", "In den Hufen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110431431", "Utbremen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110432432", "Steffensweg", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110433433", "Westend", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110434434", "Walle", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110435435", "Osterfeuerberg", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110436436", "Hohweg", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110437437", "Überseestadt", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110441441", "Lindenhof", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110442442", "Gröpelingen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110443443", "Ohlenhof", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110444444", "In den Wischen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110445445", "Oslebshausen", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110511511", "Burg-Grambke", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110512512", "Werderland", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110513513", "Burgdamm", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110514514", "Lesum", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110515515", "St. Magnus", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110521521", "Vegesack", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110522522", "Grohn", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110523523", "Schönebeck", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110524524", "Aumund-Hammersbeck", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110525525", "Fähr-Lobbendorf", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110531531", "Blumenthal", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110532532", "Rönnebeck", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110533533", "Lüssum-Bockhorn", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110534534", "Farge", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040110535535", "Rekum", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["040120000000", "Bremerhaven, Stadt", null], - ["051110000000", "Düsseldorf, Stadt", null], - ["051120000000", "Duisburg, Stadt", null], - ["051130000000", "Essen, Stadt", null], - ["051140000000", "Krefeld, Stadt", null], - ["051160000000", "Mönchengladbach, Stadt", null], - ["051170000000", "Mülheim an der Ruhr, Stadt", null], - ["051190000000", "Oberhausen, Stadt", null], - ["051200000000", "Remscheid, Stadt", null], - ["051220000000", "Solingen, Klingenstadt", null], - ["051240000000", "Wuppertal, Stadt", null], - ["051540004004", "Bedburg-Hau", null], - ["051540008008", "Emmerich am Rhein, Stadt", null], - ["051540012012", "Geldern, Stadt", null], - ["051540016016", "Goch, Stadt", null], - ["051540020020", "Issum", null], - ["051540024024", "Kalkar, Stadt", null], - ["051540028028", "Kerken", null], - ["051540032032", "Kevelaer, Stadt", null], - ["051540036036", "Kleve, Stadt", null], - ["051540040040", "Kranenburg", null], - ["051540044044", "Rees, Stadt", null], - ["051540048048", "Rheurdt", null], - ["051540052052", "Straelen, Stadt", null], - ["051540056056", "Uedem", null], - ["051540060060", "Wachtendonk", null], - ["051540064064", "Weeze", null], - ["051580004004", "Erkrath, Fundort des Neanderthalers, Stadt", null], - ["051580008008", "Haan, Stadt", null], - ["051580012012", "Heiligenhaus, Stadt", null], - ["051580016016", "Hilden, Stadt", null], - ["051580020020", "Langenfeld (Rheinland), Stadt", null], - ["051580024024", "Mettmann, Stadt", null], - ["051580026026", "Monheim am Rhein, Stadt", null], - ["051580028028", "Ratingen, Stadt", null], - ["051580032032", "Velbert, Stadt", null], - ["051580036036", "Wülfrath, Stadt", null], - ["051620004004", "Dormagen, Stadt", null], - ["051620008008", "Grevenbroich, Stadt", null], - ["051620012012", "Jüchen, Stadt", null], - ["051620016016", "Kaarst, Stadt", null], - ["051620020020", "Korschenbroich, Stadt", null], - ["051620022022", "Meerbusch, Stadt", null], - ["051620024024", "Neuss, Stadt", null], - ["051620028028", "Rommerskirchen", null], - ["051660004004", "Brüggen, Burggemeinde", null], - ["051660008008", "Grefrath, Sport- und Freizeitgemeinde", null], - ["051660012012", "Kempen, Stadt", null], - ["051660016016", "Nettetal, Stadt", null], - ["051660020020", "Niederkrüchten", null], - ["051660024024", "Schwalmtal", null], - ["051660028028", "Tönisvorst, Stadt", null], - ["051660032032", "Viersen, Stadt", null], - ["051660036036", "Willich, Stadt", null], - ["051700004004", "Alpen", null], - ["051700008008", "Dinslaken, Stadt", null], - ["051700012012", "Hamminkeln, Stadt", null], - ["051700016016", "Hünxe", null], - ["051700020020", "Kamp-Lintfort, Stadt", null], - ["051700024024", "Moers, Stadt", null], - ["051700028028", "Neukirchen-Vluyn, Stadt", null], - ["051700032032", "Rheinberg, Stadt", null], - ["051700036036", "Schermbeck", null], - ["051700040040", "Sonsbeck", null], - ["051700044044", "Voerde (Niederrhein), Stadt", null], - ["051700048048", "Wesel, Stadt", null], - ["051700052052", "Xanten, Stadt", null], - ["053140000000", "Bonn, Stadt", null], - ["053150000000", "Köln, Stadt", null], - ["053160000000", "Leverkusen, Stadt", null], - ["053340002002", "Aachen, Stadt", null], - ["053340004004", "Alsdorf, Stadt", null], - ["053340008008", "Baesweiler, Stadt", null], - ["053340012012", "Eschweiler, Stadt", null], - ["053340016016", "Herzogenrath, Stadt", null], - ["053340020020", "Monschau, Stadt", null], - ["053340024024", "Roetgen, Tor zur Eifel", null], - ["053340028028", "Simmerath", null], - ["053340032032", "Stolberg (Rhld.), Kupferstadt", null], - ["053340036036", "Würselen, Stadt", null], - ["053580004004", "Aldenhoven", null], - ["053580008008", "Düren, Stadt", null], - ["053580012012", "Heimbach, Stadt", null], - ["053580016016", "Hürtgenwald", null], - ["053580020020", "Inden", null], - ["053580024024", "Jülich, Stadt", null], - ["053580028028", "Kreuzau", null], - ["053580032032", "Langerwehe", null], - ["053580036036", "Linnich, Stadt", null], - ["053580040040", "Merzenich", null], - ["053580044044", "Nideggen, Stadt", null], - ["053580048048", "Niederzier", null], - ["053580052052", "Nörvenich", null], - ["053580056056", "Titz", null], - ["053580060060", "Vettweiß", null], - ["053620004004", "Bedburg, Stadt", null], - ["053620008008", "Bergheim, Stadt", null], - ["053620012012", "Brühl, Stadt", null], - ["053620016016", "Elsdorf, Stadt", null], - ["053620020020", "Erftstadt, Stadt", null], - ["053620024024", "Frechen, Stadt", null], - ["053620028028", "Hürth, Stadt", null], - ["053620032032", "Kerpen, Kolpingstadt", null], - ["053620036036", "Pulheim, Stadt", null], - ["053620040040", "Wesseling, Stadt", null], - ["053660004004", "Bad Münstereifel, Stadt", null], - ["053660008008", "Blankenheim", null], - ["053660012012", "Dahlem", null], - ["053660016016", "Euskirchen, Stadt", null], - ["053660020020", "Hellenthal", null], - ["053660024024", "Kall", null], - ["053660028028", "Mechernich, Stadt", null], - ["053660032032", "Nettersheim", null], - ["053660036036", "Schleiden, Stadt", null], - ["053660040040", "Weilerswist", null], - ["053660044044", "Zülpich, Stadt", null], - ["053700004004", "Erkelenz, Stadt", null], - ["053700008008", "Gangelt", null], - ["053700012012", "Geilenkirchen, Stadt", null], - ["053700016016", "Heinsberg, Stadt", null], - ["053700020020", "Hückelhoven, Stadt", null], - ["053700024024", "Selfkant", null], - ["053700028028", "Übach-Palenberg, Stadt", null], - ["053700032032", "Waldfeucht", null], - ["053700036036", "Wassenberg, Stadt", null], - ["053700040040", "Wegberg, Stadt", null], - ["053740004004", "Bergneustadt, Stadt", null], - ["053740008008", "Engelskirchen", null], - ["053740012012", "Gummersbach, Stadt", null], - ["053740016016", "Hückeswagen, Schloss-Stadt", null], - ["053740020020", "Lindlar", null], - ["053740024024", "Marienheide", null], - ["053740028028", "Morsbach", null], - ["053740032032", "Nümbrecht", null], - ["053740036036", "Radevormwald, Stadt auf der Höhe", null], - ["053740040040", "Reichshof", null], - ["053740044044", "Waldbröl, Stadt", null], - ["053740048048", "Wiehl, Stadt", null], - ["053740052052", "Wipperfürth, Hansestadt", null], - ["053780004004", "Bergisch Gladbach, Stadt", null], - ["053780008008", "Burscheid, Stadt", null], - ["053780012012", "Kürten", null], - ["053780016016", "Leichlingen (Rheinland), Blütenstadt", null], - ["053780020020", "Odenthal", null], - ["053780024024", "Overath, Stadt", null], - ["053780028028", "Rösrath, Stadt", null], - ["053780032032", "Wermelskirchen, Stadt", null], - ["053820004004", "Alfter", null], - ["053820008008", "Bad Honnef, Stadt", null], - ["053820012012", "Bornheim, Stadt", null], - ["053820016016", "Eitorf", null], - ["053820020020", "Hennef (Sieg), Stadt", null], - ["053820024024", "Königswinter, Stadt", null], - ["053820028028", "Lohmar, Stadt", null], - ["053820032032", "Meckenheim, Stadt", null], - ["053820036036", "Much", null], - ["053820040040", "Neunkirchen-Seelscheid", null], - ["053820044044", "Niederkassel, Stadt", null], - ["053820048048", "Rheinbach, Stadt", null], - ["053820052052", "Ruppichteroth", null], - ["053820056056", "Sankt Augustin, Stadt", null], - ["053820060060", "Siegburg, Stadt", null], - ["053820064064", "Swisttal", null], - ["053820068068", "Troisdorf, Stadt", null], - ["053820072072", "Wachtberg", null], - ["053820076076", "Windeck", null], - ["055120000000", "Bottrop, Stadt", null], - ["055130000000", "Gelsenkirchen, Stadt", null], - ["055150000000", "Münster, Stadt", null], - ["055540004004", "Ahaus, Stadt", null], - ["055540008008", "Bocholt, Stadt", null], - ["055540012012", "Borken, Stadt", null], - ["055540016016", "Gescher, Glockenstadt", null], - ["055540020020", "Gronau (Westf.), Stadt", null], - ["055540024024", "Heek", null], - ["055540028028", "Heiden", null], - ["055540032032", "Isselburg, Stadt", null], - ["055540036036", "Legden", null], - ["055540040040", "Raesfeld", null], - ["055540044044", "Reken", null], - ["055540048048", "Rhede, Stadt", null], - ["055540052052", "Schöppingen", null], - ["055540056056", "Stadtlohn, Stadt", null], - ["055540060060", "Südlohn", null], - ["055540064064", "Velen, Stadt", null], - ["055540068068", "Vreden, Stadt", null], - ["055580004004", "Ascheberg", null], - ["055580008008", "Billerbeck, Stadt", null], - ["055580012012", "Coesfeld, Stadt", null], - ["055580016016", "Dülmen, Stadt", null], - ["055580020020", "Havixbeck", null], - ["055580024024", "Lüdinghausen, Stadt", null], - ["055580028028", "Nordkirchen", null], - ["055580032032", "Nottuln", null], - ["055580036036", "Olfen, Stadt", null], - ["055580040040", "Rosendahl", null], - ["055580044044", "Senden", null], - ["055620004004", "Castrop-Rauxel, Stadt", null], - ["055620008008", "Datteln, Stadt", null], - ["055620012012", "Dorsten, Stadt", null], - ["055620014014", "Gladbeck, Stadt", null], - ["055620016016", "Haltern am See, Stadt", null], - ["055620020020", "Herten, Stadt", null], - ["055620024024", "Marl, Stadt", null], - ["055620028028", "Oer-Erkenschwick, Stadt", null], - ["055620032032", "Recklinghausen, Stadt", null], - ["055620036036", "Waltrop, Stadt", null], - ["055660004004", "Altenberge", null], - ["055660008008", "Emsdetten, Stadt", null], - ["055660012012", "Greven, Stadt", null], - ["055660016016", "Hörstel, Stadt", null], - ["055660020020", "Hopsten", null], - ["055660024024", "Horstmar, Stadt der Burgmannshöfe", null], - ["055660028028", "Ibbenbüren, Stadt", null], - ["055660032032", "Ladbergen", null], - ["055660036036", "Laer", null], - ["055660040040", "Lengerich, Stadt", null], - ["055660044044", "Lienen", null], - ["055660048048", "Lotte", null], - ["055660052052", "Metelen", null], - ["055660056056", "Mettingen", null], - ["055660060060", "Neuenkirchen", null], - ["055660064064", "Nordwalde", null], - ["055660068068", "Ochtrup, Stadt", null], - ["055660072072", "Recke", null], - ["055660076076", "Rheine, Stadt", null], - ["055660080080", "Saerbeck, NRW-Klimakommune", null], - ["055660084084", "Steinfurt, Stadt", null], - ["055660088088", "Tecklenburg, Stadt", null], - ["055660092092", "Westerkappeln", null], - ["055660096096", "Wettringen", null], - ["055700004004", "Ahlen, Stadt", null], - ["055700008008", "Beckum, Stadt", null], - ["055700012012", "Beelen", null], - ["055700016016", "Drensteinfurt, Stadt", null], - ["055700020020", "Ennigerloh, Stadt", null], - ["055700024024", "Everswinkel", null], - ["055700028028", "Oelde, Stadt", null], - ["055700032032", "Ostbevern", null], - ["055700036036", "Sassenberg, Stadt", null], - ["055700040040", "Sendenhorst, Stadt", null], - ["055700044044", "Telgte, Stadt", null], - ["055700048048", "Wadersloh", null], - ["055700052052", "Warendorf, Stadt", null], - ["057110000000", "Bielefeld, Stadt", null], - ["057540004004", "Borgholzhausen, Stadt", null], - ["057540008008", "Gütersloh, Stadt", null], - ["057540012012", "Halle (Westf.), Stadt", null], - ["057540016016", "Harsewinkel, Die Mähdrescherstadt", null], - ["057540020020", "Herzebrock-Clarholz", null], - ["057540024024", "Langenberg", null], - ["057540028028", "Rheda-Wiedenbrück, Stadt", null], - ["057540032032", "Rietberg, Stadt", null], - ["057540036036", "Schloß Holte-Stukenbrock, Stadt", null], - ["057540040040", "Steinhagen", null], - ["057540044044", "Verl, Stadt", null], - ["057540048048", "Versmold, Stadt", null], - ["057540052052", "Werther (Westf.), Stadt", null], - ["057580004004", "Bünde, Stadt", null], - ["057580008008", "Enger, Widukindstadt", null], - ["057580012012", "Herford, Hansestadt", null], - ["057580016016", "Hiddenhausen", null], - ["057580020020", "Kirchlengern", null], - ["057580024024", "Löhne, Stadt", null], - ["057580028028", "Rödinghausen", null], - ["057580032032", "Spenge, Stadt", null], - ["057580036036", "Vlotho, Stadt", null], - ["057620004004", "Bad Driburg, Stadt", null], - ["057620008008", "Beverungen, Stadt", null], - ["057620012012", "Borgentreich, Orgelstadt", null], - ["057620016016", "Brakel, Stadt", null], - ["057620020020", "Höxter, Stadt", null], - ["057620024024", "Marienmünster, Stadt", null], - ["057620028028", "Nieheim, Stadt", null], - ["057620032032", "Steinheim, Stadt", null], - ["057620036036", "Warburg, Hansestadt", null], - ["057620040040", "Willebadessen, Stadt", null], - ["057660004004", "Augustdorf", null], - ["057660008008", "Bad Salzuflen, Stadt", null], - ["057660012012", "Barntrup, Stadt", null], - ["057660016016", "Blomberg, Stadt", null], - ["057660020020", "Detmold, Stadt", null], - ["057660024024", "Dörentrup", null], - ["057660028028", "Extertal", null], - ["057660032032", "Horn-Bad Meinberg, Stadt", null], - ["057660036036", "Kalletal", null], - ["057660040040", "Lage, Stadt", null], - ["057660044044", "Lemgo, Stadt", null], - ["057660048048", "Leopoldshöhe", null], - ["057660052052", "Lügde, Stadt der Osterräder", null], - ["057660056056", "Oerlinghausen, Stadt", null], - ["057660060060", "Schieder-Schwalenberg, Stadt", null], - ["057660064064", "Schlangen", null], - ["057700004004", "Bad Oeynhausen, Stadt", null], - ["057700008008", "Espelkamp, Stadt", null], - ["057700012012", "Hille", null], - ["057700016016", "Hüllhorst", null], - ["057700020020", "Lübbecke, Stadt", null], - ["057700024024", "Minden, Stadt", null], - ["057700028028", "Petershagen, Stadt", null], - ["057700032032", "Porta Westfalica, Stadt", null], - ["057700036036", "Preußisch Oldendorf, Stadt", null], - ["057700040040", "Rahden, Stadt", null], - ["057700044044", "Stemwede", null], - ["057740004004", "Altenbeken", null], - ["057740008008", "Bad Lippspringe, Stadt", null], - ["057740012012", "Borchen", null], - ["057740016016", "Büren, Stadt", null], - ["057740020020", "Delbrück, Stadt", null], - ["057740024024", "Hövelhof, Sennegemeinde", null], - ["057740028028", "Lichtenau, Stadt", null], - ["057740032032", "Paderborn, Stadt", null], - ["057740036036", "Salzkotten, Stadt", null], - ["057740040040", "Bad Wünnenberg, Stadt", null], - ["059110000000", "Bochum, Stadt", null], - ["059130000000", "Dortmund, Stadt", null], - ["059140000000", "Hagen, Stadt der FernUniversität", null], - ["059150000000", "Hamm, Stadt", null], - ["059160000000", "Herne, Stadt", null], - ["059540004004", "Breckerfeld, Hansestadt", null], - ["059540008008", "Ennepetal, Stadt der Kluterthöhle", null], - ["059540012012", "Gevelsberg, Stadt", null], - ["059540016016", "Hattingen, Stadt", null], - ["059540020020", "Herdecke, Stadt", null], - ["059540024024", "Schwelm, Stadt", null], - ["059540028028", "Sprockhövel, Stadt", null], - ["059540032032", "Wetter (Ruhr), Stadt", null], - ["059540036036", "Witten, Stadt", null], - ["059580004004", "Arnsberg, Stadt", null], - ["059580008008", "Bestwig", null], - ["059580012012", "Brilon, Stadt", null], - ["059580016016", "Eslohe (Sauerland)", null], - ["059580020020", "Hallenberg, Stadt", null], - ["059580024024", "Marsberg, Stadt", null], - ["059580028028", "Medebach, Hansestadt", null], - ["059580032032", "Meschede, Kreis- und Hochschulstadt", null], - ["059580036036", "Olsberg, Stadt", null], - ["059580040040", "Schmallenberg, Stadt", null], - ["059580044044", "Sundern (Sauerland), Stadt", null], - ["059580048048", "Winterberg, Stadt", null], - ["059620004004", "Altena, Stadt", null], - ["059620008008", "Balve, Stadt", null], - ["059620012012", "Halver, Stadt", null], - ["059620016016", "Hemer, Stadt", null], - ["059620020020", "Herscheid", null], - ["059620024024", "Iserlohn, Stadt", null], - ["059620028028", "Kierspe, Stadt", null], - ["059620032032", "Lüdenscheid, Stadt", null], - ["059620036036", "Meinerzhagen, Stadt", null], - ["059620040040", "Menden (Sauerland), Stadt", null], - ["059620044044", "Nachrodt-Wiblingwerde", null], - ["059620048048", "Neuenrade, Stadt", null], - ["059620052052", "Plettenberg, Stadt", null], - ["059620056056", "Schalksmühle", null], - ["059620060060", "Werdohl, Stadt", null], - ["059660004004", "Attendorn, Hansestadt", null], - ["059660008008", "Drolshagen, Stadt", null], - ["059660012012", "Finnentrop", null], - ["059660016016", "Kirchhundem", null], - ["059660020020", "Lennestadt, Stadt", null], - ["059660024024", "Olpe, Stadt", null], - ["059660028028", "Wenden", null], - ["059700004004", "Bad Berleburg, Stadt", null], - ["059700008008", "Burbach", null], - ["059700012012", "Erndtebrück", null], - ["059700016016", "Freudenberg, Stadt", null], - ["059700020020", "Hilchenbach, Stadt", null], - ["059700024024", "Kreuztal, Stadt", null], - ["059700028028", "Bad Laasphe, Stadt", null], - ["059700032032", "Netphen, Stadt", null], - ["059700036036", "Neunkirchen", null], - ["059700040040", "Siegen, Universitätsstadt", null], - ["059700044044", "Wilnsdorf", null], - ["059740004004", "Anröchte", null], - ["059740008008", "Bad Sassendorf", null], - ["059740012012", "Ense", null], - ["059740016016", "Erwitte, Stadt", null], - ["059740020020", "Geseke, Stadt", null], - ["059740024024", "Lippetal", null], - ["059740028028", "Lippstadt, Stadt", null], - ["059740032032", "Möhnesee", null], - ["059740036036", "Rüthen, Stadt", null], - ["059740040040", "Soest, Stadt", null], - ["059740044044", "Warstein, Stadt", null], - ["059740048048", "Welver", null], - ["059740052052", "Werl, Stadt", null], - ["059740056056", "Wickede (Ruhr)", null], - ["059780004004", "Bergkamen, Stadt", null], - ["059780008008", "Bönen", null], - ["059780012012", "Fröndenberg/Ruhr, Stadt", null], - ["059780016016", "Holzwickede", null], - ["059780020020", "Kamen, Stadt", null], - ["059780024024", "Lünen, Stadt", null], - ["059780028028", "Schwerte, Hansestadt an der Ruhr", null], - ["059780032032", "Selm, Stadt", null], - ["059780036036", "Unna, Stadt", null], - ["059780040040", "Werne, Stadt", null], - ["064110000000", "Darmstadt, Wissenschaftsstadt", null], - ["064120000000", "Frankfurt am Main, Stadt", null], - ["064130000000", "Offenbach am Main, Stadt", null], - ["064140000000", "Wiesbaden, Landeshauptstadt", null], - ["064310001001", "Abtsteinach", null], - ["064310002002", "Bensheim, Stadt", null], - ["064310003003", "Biblis", null], - ["064310004004", "Birkenau", null], - ["064310005005", "Bürstadt, Stadt", null], - ["064310006006", "Einhausen", null], - ["064310007007", "Fürth", null], - ["064310008008", "Gorxheimertal", null], - ["064310009009", "Grasellenbach", null], - ["064310010010", "Groß-Rohrheim", null], - ["064310011011", "Heppenheim (Bergstraße), Kreisstadt", null], - ["064310012012", "Hirschhorn (Neckar), Stadt", null], - ["064310013013", "Lampertheim, Stadt", null], - ["064310014014", "Lautertal (Odenwald)", null], - ["064310015015", "Lindenfels, Stadt", null], - ["064310016016", "Lorsch, Karolingerstadt", null], - ["064310017017", "Mörlenbach", null], - ["064310018018", "Neckarsteinach, Stadt", null], - ["064310019019", "Rimbach", null], - ["064310020020", "Viernheim, Stadt", null], - ["064310021021", "Wald-Michelbach", null], - ["064310022022", "Zwingenberg, Stadt", null], - ["064319200200", "Michelbuch, gemfr. Gebiet", null], - ["064320001001", "Alsbach-Hähnlein", null], - ["064320002002", "Babenhausen, Stadt", null], - ["064320003003", "Bickenbach", null], - ["064320004004", "Dieburg, Stadt", null], - ["064320005005", "Eppertshausen", null], - ["064320006006", "Erzhausen", null], - ["064320007007", "Fischbachtal", null], - ["064320008008", "Griesheim, Stadt", null], - ["064320009009", "Groß-Bieberau, Stadt", null], - ["064320010010", "Groß-Umstadt, Stadt", null], - ["064320011011", "Groß-Zimmern", null], - ["064320012012", "Messel", null], - ["064320013013", "Modautal", null], - ["064320014014", "Mühltal", null], - ["064320015015", "Münster (Hessen)", null], - ["064320016016", "Ober-Ramstadt, Stadt", null], - ["064320017017", "Otzberg", null], - ["064320018018", "Pfungstadt, Stadt", null], - ["064320019019", "Reinheim, Stadt", null], - ["064320020020", "Roßdorf", null], - ["064320021021", "Schaafheim", null], - ["064320022022", "Seeheim-Jugenheim", null], - ["064320023023", "Weiterstadt, Stadt", null], - ["064330001001", "Biebesheim am Rhein", null], - ["064330002002", "Bischofsheim", null], - ["064330003003", "Büttelborn", null], - ["064330004004", "Gernsheim, Schöfferstadt", null], - ["064330005005", "Ginsheim-Gustavsburg, Stadt", null], - ["064330006006", "Groß-Gerau, Stadt", null], - ["064330007007", "Kelsterbach, Stadt", null], - ["064330008008", "Mörfelden-Walldorf, Stadt", null], - ["064330009009", "Nauheim", null], - ["064330010010", "Raunheim, Stadt", null], - ["064330011011", "Riedstadt, Büchnerstadt", null], - ["064330012012", "Rüsselsheim am Main, Stadt", null], - ["064330013013", "Stockstadt am Rhein", null], - ["064330014014", "Trebur", null], - ["064340001001", "Bad Homburg v. d. Höhe, Stadt", null], - ["064340002002", "Friedrichsdorf, Stadt", null], - ["064340003003", "Glashütten", null], - ["064340004004", "Grävenwiesbach", null], - ["064340005005", "Königstein im Taunus, Stadt", null], - ["064340006006", "Kronberg im Taunus, Stadt", null], - ["064340007007", "Neu-Anspach, Stadt", null], - ["064340008008", "Oberursel (Taunus), Stadt", null], - ["064340009009", "Schmitten", null], - ["064340010010", "Steinbach (Taunus), Stadt", null], - ["064340011011", "Usingen, Stadt", null], - ["064340012012", "Wehrheim", null], - ["064340013013", "Weilrod", null], - ["064350001001", "Bad Orb, Stadt", null], - ["064350002002", "Bad Soden-Salmünster, Stadt", null], - ["064350003003", "Biebergemünd", null], - ["064350004004", "Birstein", null], - ["064350005005", "Brachttal", null], - ["064350006006", "Bruchköbel, Stadt", null], - ["064350007007", "Erlensee, Stadt", null], - ["064350008008", "Flörsbachtal", null], - ["064350009009", "Freigericht", null], - ["064350010010", "Gelnhausen, Barbarossast., Krst.", null], - ["064350011011", "Großkrotzenburg", null], - ["064350012012", "Gründau", null], - ["064350013013", "Hammersbach", null], - ["064350014014", "Hanau, Brüder-Grimm-Stadt", null], - ["064350015015", "Hasselroth", null], - ["064350016016", "Jossgrund", null], - ["064350017017", "Langenselbold, Stadt", null], - ["064350018018", "Linsengericht", null], - ["064350019019", "Maintal, Stadt", null], - ["064350020020", "Neuberg", null], - ["064350021021", "Nidderau, Stadt", null], - ["064350022022", "Niederdorfelden", null], - ["064350023023", "Rodenbach", null], - ["064350024024", "Ronneburg", null], - ["064350025025", "Schlüchtern, Stadt", null], - ["064350026026", "Schöneck", null], - ["064350027027", "Sinntal", null], - ["064350028028", "Steinau an der Straße, Brüder-Grimm-Stadt", null], - ["064350029029", "Wächtersbach, Stadt", null], - ["064359200200", "Gutsbezirk Spessart, gemfr. Gebiet", null], - ["064360001001", "Bad Soden am Taunus, Stadt", null], - ["064360002002", "Eppstein, Stadt", null], - ["064360003003", "Eschborn, Stadt", null], - ["064360004004", "Flörsheim am Main, Stadt", null], - ["064360005005", "Hattersheim am Main, Stadt", null], - ["064360006006", "Hochheim am Main, Stadt", null], - ["064360007007", "Hofheim am Taunus, Kreisstadt", null], - ["064360008008", "Kelkheim (Taunus), Stadt", null], - ["064360009009", "Kriftel", null], - ["064360010010", "Liederbach am Taunus", null], - ["064360011011", "Schwalbach am Taunus, Stadt", null], - ["064360012012", "Sulzbach (Taunus)", null], - ["064370001001", "Bad König, Stadt", null], - ["064370003003", "Brensbach", null], - ["064370004004", "Breuberg, Stadt", null], - ["064370005005", "Brombachtal", null], - ["064370006006", "Erbach, Kreisstadt", null], - ["064370007007", "Fränkisch-Crumbach", null], - ["064370009009", "Höchst i. Odw.", null], - ["064370010010", "Lützelbach", null], - ["064370011011", "Michelstadt, Stadt", null], - ["064370012012", "Mossautal", null], - ["064370013013", "Reichelsheim (Odenwald)", null], - ["064370016016", "Oberzent, Stadt", null], - ["064380001001", "Dietzenbach, Kreisstadt", null], - ["064380002002", "Dreieich, Stadt", null], - ["064380003003", "Egelsbach", null], - ["064380004004", "Hainburg", null], - ["064380005005", "Heusenstamm, Stadt", null], - ["064380006006", "Langen (Hessen), Stadt", null], - ["064380007007", "Mainhausen", null], - ["064380008008", "Mühlheim am Main, Stadt", null], - ["064380009009", "Neu-Isenburg, Stadt", null], - ["064380010010", "Obertshausen, Stadt", null], - ["064380011011", "Rodgau, Stadt", null], - ["064380012012", "Rödermark, Stadt", null], - ["064380013013", "Seligenstadt, Einhardstadt", null], - ["064390001001", "Aarbergen", null], - ["064390002002", "Bad Schwalbach, Kreisstadt", null], - ["064390003003", "Eltville am Rhein, Stadt", null], - ["064390004004", "Geisenheim, Hochschulstadt", null], - ["064390005005", "Heidenrod", null], - ["064390006006", "Hohenstein", null], - ["064390007007", "Hünstetten", null], - ["064390008008", "Idstein, Hochschulstadt", null], - ["064390009009", "Kiedrich", null], - ["064390010010", "Lorch, Stadt", null], - ["064390011011", "Niedernhausen", null], - ["064390012012", "Oestrich-Winkel, Stadt", null], - ["064390013013", "Rüdesheim am Rhein, Stadt", null], - ["064390014014", "Schlangenbad", null], - ["064390015015", "Taunusstein, Stadt", null], - ["064390016016", "Waldems", null], - ["064390017017", "Walluf", null], - ["064400001001", "Altenstadt", null], - ["064400002002", "Bad Nauheim, Stadt", null], - ["064400003003", "Bad Vilbel, Stadt", null], - ["064400004004", "Büdingen, Stadt", null], - ["064400005005", "Butzbach, Friedrich-Ludwig-Weidig-Stadt", null], - ["064400006006", "Echzell", null], - ["064400007007", "Florstadt, Stadt", null], - ["064400008008", "Friedberg (Hessen), Kreisstadt", null], - ["064400009009", "Gedern, Stadt", null], - ["064400010010", "Glauburg", null], - ["064400011011", "Hirzenhain", null], - ["064400012012", "Karben, Stadt", null], - ["064400013013", "Kefenrod", null], - ["064400014014", "Limeshain", null], - ["064400015015", "Münzenberg, Stadt", null], - ["064400016016", "Nidda, Stadt", null], - ["064400017017", "Niddatal, Stadt", null], - ["064400018018", "Ober-Mörlen", null], - ["064400019019", "Ortenberg, Stadt", null], - ["064400020020", "Ranstadt", null], - ["064400021021", "Reichelsheim (Wetterau), Stadt", null], - ["064400022022", "Rockenberg", null], - ["064400023023", "Rosbach v. d. Höhe, Stadt", null], - ["064400024024", "Wölfersheim", null], - ["064400025025", "Wöllstadt", null], - ["065310001001", "Allendorf (Lumda), Stadt", null], - ["065310002002", "Biebertal", null], - ["065310003003", "Buseck", null], - ["065310004004", "Fernwald", null], - ["065310005005", "Gießen, Universitätsstadt", null], - ["065310006006", "Grünberg, Stadt", null], - ["065310007007", "Heuchelheim a. d. Lahn", null], - ["065310008008", "Hungen, Stadt", null], - ["065310009009", "Langgöns", null], - ["065310010010", "Laubach, Stadt", null], - ["065310011011", "Lich, Stadt", null], - ["065310012012", "Linden, Stadt", null], - ["065310013013", "Lollar, Stadt", null], - ["065310014014", "Pohlheim, Stadt", null], - ["065310015015", "Rabenau", null], - ["065310016016", "Reiskirchen", null], - ["065310017017", "Staufenberg, Stadt", null], - ["065310018018", "Wettenberg", null], - ["065320001001", "Aßlar, Stadt", null], - ["065320002002", "Bischoffen", null], - ["065320003003", "Braunfels, Stadt", null], - ["065320004004", "Breitscheid", null], - ["065320005005", "Dietzhölztal", null], - ["065320006006", "Dillenburg, Oranienstadt", null], - ["065320007007", "Driedorf", null], - ["065320008008", "Ehringshausen", null], - ["065320009009", "Eschenburg", null], - ["065320010010", "Greifenstein", null], - ["065320011011", "Haiger, Stadt", null], - ["065320012012", "Herborn, Stadt", null], - ["065320013013", "Hohenahr", null], - ["065320014014", "Hüttenberg", null], - ["065320015015", "Lahnau", null], - ["065320016016", "Leun, Stadt", null], - ["065320017017", "Mittenaar", null], - ["065320018018", "Schöffengrund", null], - ["065320019019", "Siegbach", null], - ["065320020020", "Sinn", null], - ["065320021021", "Solms, Stadt", null], - ["065320022022", "Waldsolms", null], - ["065320023023", "Wetzlar, Stadt", null], - ["065330001001", "Beselich", null], - ["065330002002", "Brechen", null], - ["065330003003", "Bad Camberg, Stadt", null], - ["065330004004", "Dornburg", null], - ["065330005005", "Elbtal", null], - ["065330006006", "Elz", null], - ["065330007007", "Hadamar, Stadt", null], - ["065330008008", "Hünfelden", null], - ["065330009009", "Limburg a. d. Lahn, Kreisstadt", null], - ["065330010010", "Löhnberg", null], - ["065330011011", "Mengerskirchen, Marktflecken", null], - ["065330012012", "Merenberg, Marktflecken", null], - ["065330013013", "Runkel, Stadt", null], - ["065330014014", "Selters (Taunus)", null], - ["065330015015", "Villmar, Marktflecken", null], - ["065330016016", "Waldbrunn (Westerwald)", null], - ["065330017017", "Weilburg, Stadt", null], - ["065330018018", "Weilmünster, Marktflecken", null], - ["065330019019", "Weinbach", null], - ["065340001001", "Amöneburg, Stadt", null], - ["065340002002", "Angelburg", null], - ["065340003003", "Bad Endbach", null], - ["065340004004", "Biedenkopf, Stadt", null], - ["065340005005", "Breidenbach", null], - ["065340006006", "Cölbe", null], - ["065340007007", "Dautphetal", null], - ["065340008008", "Ebsdorfergrund", null], - ["065340009009", "Fronhausen", null], - ["065340010010", "Gladenbach, Stadt", null], - ["065340011011", "Kirchhain, Stadt", null], - ["065340012012", "Lahntal", null], - ["065340013013", "Lohra", null], - ["065340014014", "Marburg, Universitätsstadt", null], - ["065340015015", "Münchhausen", null], - ["065340016016", "Neustadt (Hessen), Stadt", null], - ["065340017017", "Rauschenberg, Stadt", null], - ["065340018018", "Stadtallendorf, Stadt", null], - ["065340019019", "Steffenberg", null], - ["065340020020", "Weimar (Lahn)", null], - ["065340021021", "Wetter (Hessen), Stadt", null], - ["065340022022", "Wohratal", null], - ["065350001001", "Alsfeld, Stadt", null], - ["065350002002", "Antrifttal", null], - ["065350003003", "Feldatal", null], - ["065350004004", "Freiensteinau", null], - ["065350005005", "Gemünden (Felda)", null], - ["065350006006", "Grebenau, Stadt", null], - ["065350007007", "Grebenhain", null], - ["065350008008", "Herbstein, Stadt", null], - ["065350009009", "Homberg (Ohm), Stadt", null], - ["065350010010", "Kirtorf, Stadt", null], - ["065350011011", "Lauterbach (Hessen), Kreisstadt", null], - ["065350012012", "Lautertal (Vogelsberg)", null], - ["065350013013", "Mücke", null], - ["065350014014", "Romrod, Stadt", null], - ["065350015015", "Schlitz, Stadt", null], - ["065350016016", "Schotten, Stadt", null], - ["065350017017", "Schwalmtal", null], - ["065350018018", "Ulrichstein, Stadt", null], - ["065350019019", "Wartenberg", null], - ["066110000000", "Kassel, documenta-Stadt", null], - ["066310001001", "Bad Salzschlirf", null], - ["066310002002", "Burghaun, Marktgemeinde", null], - ["066310003003", "Dipperz", null], - ["066310004004", "Ebersburg", null], - ["066310005005", "Ehrenberg (Rhön)", null], - ["066310006006", "Eichenzell", null], - ["066310007007", "Eiterfeld, Marktgemeinde", null], - ["066310008008", "Flieden", null], - ["066310009009", "Fulda, Stadt", null], - ["066310010010", "Gersfeld (Rhön), Stadt", null], - ["066310011011", "Großenlüder", null], - ["066310012012", "Hilders, Marktgemeinde", null], - ["066310013013", "Hofbieber", null], - ["066310014014", "Hosenfeld", null], - ["066310015015", "Hünfeld, Konrad-Zuse-Stadt", null], - ["066310016016", "Kalbach", null], - ["066310017017", "Künzell", null], - ["066310018018", "Neuhof", null], - ["066310019019", "Nüsttal", null], - ["066310020020", "Petersberg", null], - ["066310021021", "Poppenhausen (Wasserkuppe)", null], - ["066310022022", "Rasdorf, Point-Alpha-Gemeinde", null], - ["066310023023", "Tann (Rhön), Stadt", null], - ["066320001001", "Alheim", null], - ["066320002002", "Bad Hersfeld, Kreisstadt", null], - ["066320003003", "Bebra, Stadt", null], - ["066320004004", "Breitenbach a. Herzberg", null], - ["066320005005", "Cornberg", null], - ["066320006006", "Friedewald", null], - ["066320007007", "Hauneck", null], - ["066320008008", "Haunetal", null], - ["066320009009", "Heringen (Werra), Stadt", null], - ["066320010010", "Hohenroda", null], - ["066320011011", "Kirchheim", null], - ["066320012012", "Ludwigsau", null], - ["066320013013", "Nentershausen", null], - ["066320014014", "Neuenstein", null], - ["066320015015", "Niederaula, Marktgemeinde", null], - ["066320016016", "Philippsthal (Werra), Marktgemeinde", null], - ["066320017017", "Ronshausen", null], - ["066320018018", "Rotenburg a. d. Fulda, Stadt", null], - ["066320019019", "Schenklengsfeld", null], - ["066320020020", "Wildeck", null], - ["066330001001", "Ahnatal", null], - ["066330002002", "Bad Karlshafen, Stadt", null], - ["066330003003", "Baunatal, Stadt", null], - ["066330004004", "Breuna", null], - ["066330005005", "Calden", null], - ["066330006006", "Bad Emstal", null], - ["066330007007", "Espenau", null], - ["066330008008", "Fuldabrück", null], - ["066330009009", "Fuldatal", null], - ["066330010010", "Grebenstein, Stadt", null], - ["066330011011", "Habichtswald", null], - ["066330012012", "Helsa", null], - ["066330013013", "Hofgeismar, Stadt", null], - ["066330014014", "Immenhausen, Stadt", null], - ["066330015015", "Kaufungen", null], - ["066330016016", "Liebenau, Stadt", null], - ["066330017017", "Lohfelden", null], - ["066330018018", "Naumburg, Stadt", null], - ["066330019019", "Nieste", null], - ["066330020020", "Niestetal", null], - ["066330022022", "Reinhardshagen", null], - ["066330023023", "Schauenburg", null], - ["066330024024", "Söhrewald", null], - ["066330025025", "Trendelburg, Stadt", null], - ["066330026026", "Vellmar, Stadt", null], - ["066330028028", "Wolfhagen, Hans-Staden-Stadt", null], - ["066330029029", "Zierenberg, Stadt", null], - ["066330030030", "Wesertal", null], - ["066339200200", "Gutsbezirk Reinhardswald, gemfr. Gebiet", null], - ["066340001001", "Borken (Hessen), Stadt", null], - ["066340002002", "Edermünde", null], - ["066340003003", "Felsberg, Stadt", null], - ["066340004004", "Frielendorf, Marktflecken", null], - ["066340005005", "Fritzlar, Dom- und Kaiserstadt", null], - ["066340006006", "Gilserberg", null], - ["066340007007", "Gudensberg, Stadt", null], - ["066340008008", "Guxhagen", null], - ["066340009009", "Homberg (Efze), Reformationsstadt, Kreisstadt", null], - ["066340010010", "Jesberg", null], - ["066340011011", "Knüllwald", null], - ["066340012012", "Körle", null], - ["066340013013", "Malsfeld", null], - ["066340014014", "Melsungen, Stadt", null], - ["066340015015", "Morschen", null], - ["066340016016", "Neuental", null], - ["066340017017", "Neukirchen, Stadt", null], - ["066340018018", "Niedenstein, Stadt", null], - ["066340019019", "Oberaula", null], - ["066340020020", "Ottrau", null], - ["066340021021", "Schrecksbach", null], - ["066340022022", "Schwalmstadt, Konfirmationsstadt", null], - ["066340023023", "Schwarzenborn, Stadt", null], - ["066340024024", "Spangenberg, Liebenbachstadt", null], - ["066340025025", "Wabern", null], - ["066340026026", "Willingshausen", null], - ["066340027027", "Bad Zwesten", null], - ["066350001001", "Allendorf (Eder)", null], - ["066350002002", "Bad Arolsen, Stadt", null], - ["066350003003", "Bad Wildungen, Stadt", null], - ["066350004004", "Battenberg (Eder), Stadt", null], - ["066350005005", "Bromskirchen", null], - ["066350006006", "Burgwald", null], - ["066350007007", "Diemelsee", null], - ["066350008008", "Diemelstadt, Stadt", null], - ["066350009009", "Edertal, Nationalparkgemeinde", null], - ["066350010010", "Frankenau, Nationalparkstadt", null], - ["066350011011", "Frankenberg (Eder), Philipp-Soldan-Stadt", null], - ["066350012012", "Gemünden (Wohra), Stadt", null], - ["066350013013", "Haina (Kloster)", null], - ["066350014014", "Hatzfeld (Eder), Stadt", null], - ["066350015015", "Korbach, Hansestadt, Kreisstadt", null], - ["066350016016", "Lichtenfels, Stadt", null], - ["066350017017", "Rosenthal, Stadt", null], - ["066350018018", "Twistetal", null], - ["066350019019", "Vöhl, Nationalparkgemeinde", null], - ["066350020020", "Volkmarsen, Stadt", null], - ["066350021021", "Waldeck, Stadt", null], - ["066350022022", "Willingen (Upland)", null], - ["066360001001", "Bad Sooden-Allendorf, Stadt", null], - ["066360002002", "Berkatal", null], - ["066360003003", "Eschwege, Kreisstadt", null], - ["066360004004", "Großalmerode, Stadt", null], - ["066360005005", "Herleshausen", null], - ["066360006006", "Hessisch Lichtenau, Stadt", null], - ["066360007007", "Meinhard", null], - ["066360008008", "Meißner", null], - ["066360009009", "Neu-Eichenberg", null], - ["066360010010", "Ringgau", null], - ["066360011011", "Sontra, Stadt", null], - ["066360012012", "Waldkappel, Stadt", null], - ["066360013013", "Wanfried, Stadt", null], - ["066360014014", "Wehretal", null], - ["066360015015", "Weißenborn", null], - ["066360016016", "Witzenhausen, Stadt", null], - ["066369200200", "Gutsbezirk Kaufunger Wald, gemfr. Gebiet", null], - ["070009999999", "Gemeinsames deutsch-luxemburgisches Hoheitsgebiet", null], - ["071110000000", "Koblenz, Stadt", null], - ["071310007007", "Bad Neuenahr-Ahrweiler, Stadt", null], - ["071310070070", "Remagen, Stadt", null], - ["071310077077", "Sinzig, Stadt", null], - ["071310090090", "Grafschaft", null], - ["071315001001", "Adenau, Stadt", null], - ["071315001004", "Antweiler", null], - ["071315001005", "Aremberg", null], - ["071315001008", "Barweiler", null], - ["071315001009", "Bauler", null], - ["071315001015", "Dankerath", null], - ["071315001018", "Dorsel", null], - ["071315001021", "Eichenbach", null], - ["071315001022", "Fuchshofen", null], - ["071315001026", "Harscheid", null], - ["071315001028", "Herschbroich", null], - ["071315001030", "Hoffeld", null], - ["071315001032", "Honerath", null], - ["071315001033", "Hümmel", null], - ["071315001034", "Insul", null], - ["071315001037", "Kaltenborn", null], - ["071315001042", "Kottenborn", null], - ["071315001044", "Leimbach", null], - ["071315001050", "Meuspath", null], - ["071315001051", "Müllenbach", null], - ["071315001052", "Müsch", null], - ["071315001058", "Nürburg", null], - ["071315001062", "Ohlenhard", null], - ["071315001065", "Pomster", null], - ["071315001066", "Quiddelbach", null], - ["071315001069", "Reifferscheid", null], - ["071315001072", "Rodder", null], - ["071315001074", "Schuld", null], - ["071315001075", "Senscheid", null], - ["071315001076", "Sierscheid", null], - ["071315001079", "Trierscheid", null], - ["071315001082", "Wershofen", null], - ["071315001083", "Wiesemscheid", null], - ["071315001084", "Wimbach", null], - ["071315001085", "Winnerath", null], - ["071315001086", "Wirft", null], - ["071315001501", "Dümpelfeld", null], - ["071315002002", "Ahrbrück", null], - ["071315002003", "Altenahr", null], - ["071315002011", "Berg", null], - ["071315002017", "Dernau", null], - ["071315002027", "Heckenbach", null], - ["071315002029", "Hönningen", null], - ["071315002036", "Kalenborn", null], - ["071315002039", "Kesseling", null], - ["071315002040", "Kirchsahr", null], - ["071315002047", "Lind", null], - ["071315002049", "Mayschoß", null], - ["071315002068", "Rech", null], - ["071315003006", "Bad Breisig, Stadt", null], - ["071315003014", "Brohl-Lützing", null], - ["071315003025", "Gönnersdorf", null], - ["071315003081", "Waldorf", null], - ["071315004016", "Dedenbach", null], - ["071315004041", "Königsfeld", null], - ["071315004054", "Niederdürenbach", null], - ["071315004055", "Niederzissen", null], - ["071315004059", "Oberdürenbach", null], - ["071315004060", "Oberzissen", null], - ["071315004073", "Schalkenbach", null], - ["071315004201", "Brenk", null], - ["071315004202", "Burgbrohl", null], - ["071315004204", "Galenberg", null], - ["071315004205", "Glees", null], - ["071315004206", "Hohenleimbach", null], - ["071315004208", "Spessart", null], - ["071315004209", "Wassenach", null], - ["071315004210", "Wehr", null], - ["071315004211", "Weibern", null], - ["071315004502", "Kempenich", null], - ["071325003018", "Daaden, Stadt", null], - ["071325003019", "Derschen", null], - ["071325003026", "Emmerzhausen", null], - ["071325003036", "Friedewald", null], - ["071325003050", "Herdorf, Stadt", null], - ["071325003068", "Mauden", null], - ["071325003075", "Niederdreisbach", null], - ["071325003079", "Nisterberg", null], - ["071325003101", "Schutzbach", null], - ["071325003113", "Weitefeld", null], - ["071325006007", "Birkenbeul", null], - ["071325006010", "Bitzen", null], - ["071325006013", "Breitscheidt", null], - ["071325006014", "Bruchertseifen", null], - ["071325006028", "Etzbach", null], - ["071325006034", "Forst", null], - ["071325006038", "Fürthen", null], - ["071325006044", "Hamm (Sieg)", null], - ["071325006077", "Niederirsen", null], - ["071325006091", "Pracht", null], - ["071325006096", "Roth", null], - ["071325006102", "Seelbach bei Hamm (Sieg)", null], - ["071325007012", "Brachbach", null], - ["071325007037", "Friesenhagen", null], - ["071325007045", "Harbach", null], - ["071325007063", "Kirchen (Sieg), Stadt", null], - ["071325007072", "Mudersbach", null], - ["071325007076", "Niederfischbach", null], - ["071325008008", "Birken-Honigsessen", null], - ["071325008011", "Mittelhof", null], - ["071325008054", "Hövels", null], - ["071325008080", "Katzwinkel (Sieg)", null], - ["071325008105", "Selbach (Sieg)", null], - ["071325008117", "Wissen, Stadt", null], - ["071325009002", "Alsdorf", null], - ["071325009006", "Betzdorf, Stadt", null], - ["071325009020", "Dickendorf", null], - ["071325009024", "Elben", null], - ["071325009025", "Elkenroth", null], - ["071325009030", "Fensdorf", null], - ["071325009039", "Gebhardshain", null], - ["071325009042", "Grünebach", null], - ["071325009059", "Kausen", null], - ["071325009066", "Malberg", null], - ["071325009071", "Molzhain", null], - ["071325009073", "Nauroth", null], - ["071325009095", "Rosenheim (Landkreis Altenkirchen)", null], - ["071325009098", "Scheuerfeld", null], - ["071325009107", "Steinebach/ Sieg", null], - ["071325009108", "Steineroth", null], - ["071325009111", "Wallmenroth", null], - ["071325010001", "Almersbach", null], - ["071325010004", "Bachenberg", null], - ["071325010005", "Berzhausen", null], - ["071325010009", "Birnbach", null], - ["071325010015", "Bürdenbach", null], - ["071325010016", "Burglahr", null], - ["071325010017", "Busenhausen", null], - ["071325010022", "Eichelhardt", null], - ["071325010023", "Eichen", null], - ["071325010027", "Ersfeld", null], - ["071325010029", "Eulenberg", null], - ["071325010031", "Fiersbach", null], - ["071325010032", "Flammersfeld", null], - ["071325010033", "Fluterschen", null], - ["071325010035", "Forstmehren", null], - ["071325010040", "Gieleroth", null], - ["071325010041", "Giershausen", null], - ["071325010043", "Güllesheim", null], - ["071325010046", "Hasselbach", null], - ["071325010047", "Helmenzen", null], - ["071325010048", "Helmeroth", null], - ["071325010049", "Hemmelzen", null], - ["071325010051", "Heupelzen", null], - ["071325010052", "Hilgenroth", null], - ["071325010053", "Hirz-Maulsbach", null], - ["071325010055", "Horhausen (Westerwald)", null], - ["071325010056", "Idelberg", null], - ["071325010057", "Ingelbach", null], - ["071325010058", "Isert", null], - ["071325010060", "Kescheid", null], - ["071325010061", "Kettenhausen", null], - ["071325010062", "Kircheib", null], - ["071325010064", "Kraam", null], - ["071325010065", "Krunkel", null], - ["071325010067", "Mammelzen", null], - ["071325010069", "Mehren", null], - ["071325010070", "Michelbach (Westerwald)", null], - ["071325010078", "Niedersteinebach", null], - ["071325010081", "Obererbach (Westerwald)", null], - ["071325010082", "Oberirsen", null], - ["071325010083", "Oberlahr", null], - ["071325010085", "Obersteinebach", null], - ["071325010086", "Oberwambach", null], - ["071325010087", "Ölsen", null], - ["071325010088", "Orfgen", null], - ["071325010089", "Peterslahr", null], - ["071325010090", "Pleckhausen", null], - ["071325010092", "Racksen", null], - ["071325010093", "Reiferscheid", null], - ["071325010094", "Rettersen", null], - ["071325010097", "Rott", null], - ["071325010099", "Schöneberg", null], - ["071325010100", "Schürdt", null], - ["071325010103", "Seelbach (Westerwald)", null], - ["071325010104", "Seifen", null], - ["071325010106", "Sörth", null], - ["071325010109", "Stürzelbach", null], - ["071325010110", "Volkerzen", null], - ["071325010112", "Walterschen", null], - ["071325010114", "Werkhausen", null], - ["071325010115", "Weyerbusch", null], - ["071325010116", "Willroth", null], - ["071325010118", "Wölmersen", null], - ["071325010119", "Ziegenhain", null], - ["071325010201", "Berod bei Hachenburg", null], - ["071325010501", "Altenkirchen (Westerwald), Stadt", null], - ["071325010502", "Neitersen", null], - ["071330006006", "Bad Kreuznach, Stadt", null], - ["071335001003", "Altenbamberg", null], - ["071335001012", "Biebelsheim", null], - ["071335001030", "Feilbingert", null], - ["071335001031", "Frei-Laubersheim", null], - ["071335001032", "Fürfeld", null], - ["071335001037", "Hackenheim", null], - ["071335001039", "Hallgarten", null], - ["071335001045", "Hochstätten", null], - ["071335001069", "Neu-Bamberg", null], - ["071335001078", "Pfaffen-Schwabenheim", null], - ["071335001080", "Pleitersheim", null], - ["071335001104", "Tiefenthal", null], - ["071335001106", "Volxheim", null], - ["071335006002", "Allenfeld", null], - ["071335006004", "Argenschwang", null], - ["071335006013", "Bockenau", null], - ["071335006014", "Boos", null], - ["071335006015", "Braunweiler", null], - ["071335006019", "Burgsponheim", null], - ["071335006021", "Dalberg", null], - ["071335006027", "Duchroth", null], - ["071335006033", "Gebroth", null], - ["071335006036", "Gutenberg", null], - ["071335006040", "Hargesheim", null], - ["071335006044", "Hergenfeld", null], - ["071335006048", "Hüffelsheim", null], - ["071335006061", "Mandel", null], - ["071335006068", "Münchwald", null], - ["071335006070", "Niederhausen", null], - ["071335006071", "Norheim", null], - ["071335006074", "Oberhausen an der Nahe", null], - ["071335006075", "Oberstreit", null], - ["071335006086", "Roxheim", null], - ["071335006088", "Sankt Katharinen", null], - ["071335006089", "Schloßböckelheim", null], - ["071335006098", "Sommerloch", null], - ["071335006099", "Spabrücken", null], - ["071335006100", "Spall", null], - ["071335006101", "Sponheim", null], - ["071335006105", "Traisen", null], - ["071335006107", "Waldböckelheim", null], - ["071335006109", "Wallhausen", null], - ["071335006112", "Weinsheim", null], - ["071335006115", "Winterbach", null], - ["071335006117", "Rüdesheim", null], - ["071335009008", "Bärenbach", null], - ["071335009010", "Becherbach bei Kirn", null], - ["071335009016", "Brauweiler", null], - ["071335009038", "Hahnenbach", null], - ["071335009041", "Heimweiler", null], - ["071335009042", "Heinzenberg", null], - ["071335009043", "Hennweiler", null], - ["071335009046", "Hochstetten-Dhaun", null], - ["071335009047", "Horbach", null], - ["071335009052", "Kirn, Stadt", null], - ["071335009059", "Limbach", null], - ["071335009063", "Meckenbach", null], - ["071335009073", "Oberhausen bei Kirn", null], - ["071335009077", "Otzweiler", null], - ["071335009096", "Simmertal", null], - ["071335009113", "Weitersborn", null], - ["071335009201", "Bruschied", null], - ["071335009202", "Kellenbach", null], - ["071335009203", "Königsau", null], - ["071335009204", "Schneppenbach", null], - ["071335009205", "Schwarzerden", null], - ["071335010001", "Abtweiler", null], - ["071335010005", "Auen", null], - ["071335010009", "Bärweiler", null], - ["071335010011", "Becherbach", null], - ["071335010017", "Breitenheim", null], - ["071335010020", "Callbach", null], - ["071335010022", "Daubach", null], - ["071335010024", "Desloch", null], - ["071335010049", "Hundsbach", null], - ["071335010050", "Ippenschied", null], - ["071335010051", "Jeckenbach", null], - ["071335010053", "Kirschroth", null], - ["071335010055", "Langenthal", null], - ["071335010057", "Lauschied", null], - ["071335010058", "Lettweiler", null], - ["071335010060", "Löllbach", null], - ["071335010062", "Martinstein", null], - ["071335010064", "Meddersheim", null], - ["071335010065", "Meisenheim, Stadt", null], - ["071335010066", "Merxheim", null], - ["071335010067", "Monzingen", null], - ["071335010072", "Nußbaum", null], - ["071335010076", "Odernheim am Glan", null], - ["071335010081", "Raumbach", null], - ["071335010082", "Rehbach", null], - ["071335010083", "Rehborn", null], - ["071335010084", "Reiffelbach", null], - ["071335010090", "Schmittweiler", null], - ["071335010092", "Schweinschied", null], - ["071335010094", "Seesbach", null], - ["071335010102", "Staudernheim", null], - ["071335010111", "Weiler bei Monzingen", null], - ["071335010116", "Winterburg", null], - ["071335010501", "Bad Sobernheim, Stadt", null], - ["071335011018", "Bretzenheim", null], - ["071335011023", "Daxweiler", null], - ["071335011025", "Dörrebach", null], - ["071335011026", "Dorsheim", null], - ["071335011028", "Eckenroth", null], - ["071335011035", "Guldental", null], - ["071335011054", "Langenlonsheim", null], - ["071335011056", "Laubenheim", null], - ["071335011085", "Roth", null], - ["071335011087", "Rümmelsheim", null], - ["071335011091", "Schöneberg", null], - ["071335011093", "Schweppenhausen", null], - ["071335011095", "Seibersbach", null], - ["071335011103", "Stromberg, Stadt", null], - ["071335011108", "Waldlaubersheim", null], - ["071335011110", "Warmsroth", null], - ["071335011114", "Windesheim", null], - ["071340045045", "Idar-Oberstein, Stadt", null], - ["071345001005", "Baumholder, Stadt", null], - ["071345001007", "Berglangenbach", null], - ["071345001008", "Berschweiler bei Baumholder", null], - ["071345001021", "Eckersweiler", null], - ["071345001026", "Fohren-Linden", null], - ["071345001027", "Frauenberg", null], - ["071345001033", "Hahnweiler", null], - ["071345001036", "Heimbach", null], - ["071345001051", "Leitzweiler", null], - ["071345001054", "Mettweiler", null], - ["071345001068", "Reichenbach", null], - ["071345001073", "Rohrbach", null], - ["071345001074", "Rückweiler", null], - ["071345001075", "Ruschberg", null], - ["071345002001", "Abentheuer", null], - ["071345002002", "Achtelsbach", null], - ["071345002010", "Birkenfeld, Stadt", null], - ["071345002011", "Börfink", null], - ["071345002015", "Brücken", null], - ["071345002016", "Buhlenberg", null], - ["071345002018", "Dambach", null], - ["071345002020", "Dienstweiler", null], - ["071345002022", "Elchweiler", null], - ["071345002023", "Ellenberg", null], - ["071345002024", "Ellweiler", null], - ["071345002029", "Gimbweiler", null], - ["071345002031", "Gollenberg", null], - ["071345002034", "Hattgenstein", null], - ["071345002042", "Hoppstädten-Weiersbach", null], - ["071345002048", "Kronweiler", null], - ["071345002050", "Leisel", null], - ["071345002053", "Meckenbach", null], - ["071345002057", "Niederbrombach", null], - ["071345002058", "Niederhambach", null], - ["071345002061", "Nohen", null], - ["071345002062", "Oberbrombach", null], - ["071345002063", "Oberhambach", null], - ["071345002070", "Rimsberg", null], - ["071345002071", "Rinzenberg", null], - ["071345002072", "Rötsweiler-Nockenthal", null], - ["071345002078", "Schmißberg", null], - ["071345002080", "Schwollen", null], - ["071345002084", "Siesbach", null], - ["071345002085", "Sonnenberg-Winnenberg", null], - ["071345002094", "Wilzenberg-Hußweiler", null], - ["071345005003", "Allenbach", null], - ["071345005004", "Asbach", null], - ["071345005006", "Bergen", null], - ["071345005009", "Berschweiler bei Kirn", null], - ["071345005012", "Bollenbach", null], - ["071345005013", "Breitenthal", null], - ["071345005014", "Bruchweiler", null], - ["071345005017", "Bundenbach", null], - ["071345005019", "Dickesbach", null], - ["071345005025", "Fischbach", null], - ["071345005028", "Gerach", null], - ["071345005030", "Gösenroth", null], - ["071345005032", "Griebelschied", null], - ["071345005035", "Hausen", null], - ["071345005037", "Hellertshausen", null], - ["071345005038", "Herborn", null], - ["071345005039", "Herrstein", null], - ["071345005040", "Hettenrodt", null], - ["071345005041", "Hintertiefenbach", null], - ["071345005043", "Horbruch", null], - ["071345005044", "Hottenbach", null], - ["071345005046", "Kempfeld", null], - ["071345005047", "Kirschweiler", null], - ["071345005049", "Krummenau", null], - ["071345005052", "Mackenrodt", null], - ["071345005055", "Mittelreidenbach", null], - ["071345005056", "Mörschied", null], - ["071345005059", "Niederhosenbach", null], - ["071345005060", "Niederwörresbach", null], - ["071345005064", "Oberhosenbach", null], - ["071345005065", "Oberkirn", null], - ["071345005066", "Oberreidenbach", null], - ["071345005067", "Oberwörresbach", null], - ["071345005069", "Rhaunen", null], - ["071345005076", "Schauren", null], - ["071345005077", "Schmidthachenbach", null], - ["071345005079", "Schwerbach", null], - ["071345005081", "Sensweiler", null], - ["071345005082", "Sien", null], - ["071345005083", "Sienhachenbach", null], - ["071345005086", "Sonnschied", null], - ["071345005087", "Stipshausen", null], - ["071345005088", "Sulzbach", null], - ["071345005089", "Veitsrodt", null], - ["071345005090", "Vollmersbach", null], - ["071345005091", "Weiden", null], - ["071345005092", "Weitersbach", null], - ["071345005093", "Wickenrodt", null], - ["071345005095", "Wirschweiler", null], - ["071345005502", "Langweiler", null], - ["071355001007", "Beilstein", null], - ["071355001012", "Bremm", null], - ["071355001015", "Briedern", null], - ["071355001017", "Bruttig-Fankel", null], - ["071355001020", "Cochem, Stadt", null], - ["071355001021", "Dohr", null], - ["071355001024", "Ediger-Eller", null], - ["071355001025", "Ellenz-Poltersdorf", null], - ["071355001027", "Ernst", null], - ["071355001029", "Faid", null], - ["071355001036", "Greimersburg", null], - ["071355001049", "Klotten", null], - ["071355001053", "Lieg", null], - ["071355001056", "Lütz", null], - ["071355001060", "Mesenich", null], - ["071355001065", "Moselkern", null], - ["071355001066", "Müden (Mosel)", null], - ["071355001069", "Nehren", null], - ["071355001072", "Pommern", null], - ["071355001079", "Senheim", null], - ["071355001082", "Treis-Karden", null], - ["071355001086", "Valwig", null], - ["071355001090", "Wirfus", null], - ["071355002009", "Binningen", null], - ["071355002011", "Brachtendorf", null], - ["071355002014", "Brieden", null], - ["071355002016", "Brohl", null], - ["071355002022", "Dünfus", null], - ["071355002023", "Düngenheim", null], - ["071355002026", "Eppenberg", null], - ["071355002028", "Eulgem", null], - ["071355002031", "Forst (Eifel)", null], - ["071355002033", "Gamlen", null], - ["071355002038", "Hambuch", null], - ["071355002040", "Hauroth", null], - ["071355002042", "Illerich", null], - ["071355002043", "Kaifenheim", null], - ["071355002044", "Kail", null], - ["071355002045", "Kaisersesch, Stadt", null], - ["071355002046", "Kalenborn", null], - ["071355002051", "Landkern", null], - ["071355002052", "Laubach", null], - ["071355002058", "Masburg", null], - ["071355002062", "Möntenich", null], - ["071355002067", "Müllenbach", null], - ["071355002075", "Roes", null], - ["071355002084", "Urmersbach", null], - ["071355002093", "Zettingen", null], - ["071355002502", "Leienkaul", null], - ["071355003002", "Alflen", null], - ["071355003005", "Auderath", null], - ["071355003008", "Beuren", null], - ["071355003018", "Büchel", null], - ["071355003030", "Filz", null], - ["071355003034", "Gevenich", null], - ["071355003035", "Gillenbeuren", null], - ["071355003048", "Kliding", null], - ["071355003057", "Lutzerath", null], - ["071355003078", "Schmitt", null], - ["071355003083", "Ulmen, Stadt", null], - ["071355003085", "Urschmitt", null], - ["071355003087", "Wagenhausen", null], - ["071355003089", "Weiler", null], - ["071355003091", "Wollmerath", null], - ["071355003501", "Bad Bertrich", null], - ["071355005001", "Alf", null], - ["071355005003", "Altlay", null], - ["071355005004", "Altstrimmig", null], - ["071355005010", "Blankenrath", null], - ["071355005013", "Briedel", null], - ["071355005019", "Bullay", null], - ["071355005032", "Forst (Hunsrück)", null], - ["071355005037", "Grenderich", null], - ["071355005039", "Haserich", null], - ["071355005041", "Hesweiler", null], - ["071355005054", "Liesenich", null], - ["071355005061", "Mittelstrimmig", null], - ["071355005064", "Moritzheim", null], - ["071355005068", "Neef", null], - ["071355005070", "Panzweiler", null], - ["071355005071", "Peterswald-Löffelscheid", null], - ["071355005073", "Pünderich", null], - ["071355005074", "Reidenhausen", null], - ["071355005076", "Sankt Aldegund", null], - ["071355005077", "Schauren", null], - ["071355005080", "Sosberg", null], - ["071355005081", "Tellig", null], - ["071355005088", "Walhausen", null], - ["071355005092", "Zell (Mosel), Stadt", null], - ["071370003003", "Andernach, Stadt", null], - ["071370068068", "Mayen, Stadt", null], - ["071370203203", "Bendorf, Stadt", null], - ["071375001056", "Kretz", null], - ["071375001057", "Kruft", null], - ["071375001081", "Nickenich", null], - ["071375001088", "Plaidt", null], - ["071375001096", "Saffig", null], - ["071375002023", "Einig", null], - ["071375002027", "Gappenach", null], - ["071375002029", "Gering", null], - ["071375002030", "Gierschnach", null], - ["071375002041", "Kalt", null], - ["071375002048", "Kerben", null], - ["071375002053", "Kollig", null], - ["071375002065", "Lonnig", null], - ["071375002070", "Mertloch", null], - ["071375002080", "Naunheim", null], - ["071375002086", "Ochtendung", null], - ["071375002087", "Pillig", null], - ["071375002089", "Polch, Stadt", null], - ["071375002095", "Rüber", null], - ["071375002102", "Trimbs", null], - ["071375002112", "Welling", null], - ["071375002114", "Wierschem", null], - ["071375002501", "Münstermaifeld, Stadt", null], - ["071375003001", "Acht", null], - ["071375003004", "Anschau", null], - ["071375003006", "Arft", null], - ["071375003007", "Baar", null], - ["071375003011", "Bermel", null], - ["071375003014", "Boos", null], - ["071375003019", "Ditscheid", null], - ["071375003025", "Ettringen", null], - ["071375003034", "Hausten", null], - ["071375003035", "Herresbach", null], - ["071375003036", "Hirten", null], - ["071375003043", "Kehrig", null], - ["071375003049", "Kirchwald", null], - ["071375003055", "Kottenheim", null], - ["071375003060", "Langenfeld", null], - ["071375003061", "Langscheid", null], - ["071375003063", "Lind", null], - ["071375003066", "Luxem", null], - ["071375003074", "Monreal", null], - ["071375003077", "Münk", null], - ["071375003079", "Nachtsheim", null], - ["071375003092", "Reudelsterz", null], - ["071375003097", "Sankt Johann", null], - ["071375003099", "Siebenbach", null], - ["071375003105", "Virneburg", null], - ["071375003110", "Weiler", null], - ["071375003113", "Welschenbach", null], - ["071375004008", "Bell", null], - ["071375004069", "Mendig, Stadt", null], - ["071375004093", "Rieden", null], - ["071375004101", "Thür", null], - ["071375004106", "Volkesfeld", null], - ["071375007218", "Niederwerth", null], - ["071375007224", "Urbar", null], - ["071375007226", "Vallendar, Stadt", null], - ["071375007229", "Weitersburg", null], - ["071375008202", "Bassenheim", null], - ["071375008209", "Kaltenengers", null], - ["071375008211", "Kettig", null], - ["071375008216", "Mülheim-Kärlich, Stadt", null], - ["071375008222", "Sankt Sebastian", null], - ["071375008225", "Urmitz", null], - ["071375008228", "Weißenthurm, Stadt", null], - ["071375009201", "Alken", null], - ["071375009204", "Brey", null], - ["071375009205", "Brodenbach", null], - ["071375009206", "Burgen", null], - ["071375009207", "Dieblich", null], - ["071375009208", "Hatzenport", null], - ["071375009212", "Kobern-Gondorf", null], - ["071375009214", "Löf", null], - ["071375009215", "Macken", null], - ["071375009217", "Niederfell", null], - ["071375009219", "Nörtershausen", null], - ["071375009220", "Oberfell", null], - ["071375009221", "Rhens, Stadt", null], - ["071375009223", "Spay", null], - ["071375009227", "Waldesch", null], - ["071375009230", "Winningen", null], - ["071375009231", "Wolken", null], - ["071375009504", "Lehmen", null], - ["071380045045", "Neuwied, Stadt", null], - ["071385001003", "Asbach", null], - ["071385001044", "Neustadt (Wied)", null], - ["071385001077", "Windhagen", null], - ["071385001080", "Buchholz (Westerwald)", null], - ["071385002004", "Bad Hönningen, Stadt", null], - ["071385002024", "Hammerstein", null], - ["071385002038", "Leutesdorf", null], - ["071385002063", "Rheinbrohl", null], - ["071385003012", "Dierdorf, Stadt", null], - ["071385003023", "Großmaischeid", null], - ["071385003031", "Isenburg", null], - ["071385003034", "Kleinmaischeid", null], - ["071385003069", "Stebach", null], - ["071385003201", "Marienhausen", null], - ["071385004009", "Dattenberg", null], - ["071385004037", "Leubsdorf", null], - ["071385004041", "Linz am Rhein, Stadt", null], - ["071385004055", "Ockenfels", null], - ["071385004068", "Sankt Katharinen (Landkreis Neuwied)", null], - ["071385004075", "Vettelschoß", null], - ["071385004501", "Kasbach-Ohlenberg", null], - ["071385005011", "Dernbach", null], - ["071385005013", "Döttesfeld", null], - ["071385005014", "Dürrholz", null], - ["071385005025", "Hanroth", null], - ["071385005027", "Harschbach", null], - ["071385005040", "Linkenbach", null], - ["071385005048", "Niederhofen", null], - ["071385005050", "Niederwambach", null], - ["071385005052", "Oberdreis", null], - ["071385005057", "Puderbach", null], - ["071385005058", "Ratzert", null], - ["071385005059", "Raubach", null], - ["071385005064", "Rodenbach bei Puderbach", null], - ["071385005070", "Steimel", null], - ["071385005074", "Urbach", null], - ["071385005078", "Woldert", null], - ["071385007008", "Bruchhausen", null], - ["071385007019", "Erpel", null], - ["071385007062", "Rheinbreitbach", null], - ["071385007073", "Unkel, Stadt", null], - ["071385009002", "Anhausen", null], - ["071385009005", "Bonefeld", null], - ["071385009006", "Breitscheid", null], - ["071385009007", "Hausen (Wied)", null], - ["071385009010", "Datzeroth", null], - ["071385009015", "Ehlscheid", null], - ["071385009026", "Hardert", null], - ["071385009030", "Hümmerich", null], - ["071385009036", "Kurtscheid", null], - ["071385009042", "Meinborn", null], - ["071385009043", "Melsbach", null], - ["071385009047", "Niederbreitbach", null], - ["071385009053", "Oberhonnefeld-Gierend", null], - ["071385009054", "Oberraden", null], - ["071385009061", "Rengsdorf", null], - ["071385009065", "Roßbach", null], - ["071385009066", "Rüscheid", null], - ["071385009071", "Straßenhaus", null], - ["071385009072", "Thalhausen", null], - ["071385009076", "Waldbreitbach", null], - ["071400501501", "Boppard, Stadt", null], - ["071405003001", "Alterkülz", null], - ["071405003009", "Bell (Hunsrück)", null], - ["071405003010", "Beltheim", null], - ["071405003018", "Braunshorn", null], - ["071405003021", "Buch", null], - ["071405003042", "Gödenroth", null], - ["071405003046", "Hasselbach", null], - ["071405003055", "Hollnich", null], - ["071405003064", "Kastellaun, Stadt", null], - ["071405003073", "Korweiler", null], - ["071405003095", "Michelbach", null], - ["071405003131", "Roth", null], - ["071405003147", "Spesenroth", null], - ["071405003153", "Uhler", null], - ["071405003202", "Dommershausen", null], - ["071405003204", "Mastershausen", null], - ["071405003502", "Lahr", null], - ["071405003503", "Mörsdorf", null], - ["071405003504", "Zilshausen", null], - ["071405004006", "Bärenbach", null], - ["071405004007", "Belg", null], - ["071405004024", "Büchenbeuren", null], - ["071405004028", "Dickenschied", null], - ["071405004029", "Dill", null], - ["071405004030", "Dillendorf", null], - ["071405004040", "Gehlweiler", null], - ["071405004041", "Gemünden", null], - ["071405004044", "Hahn", null], - ["071405004048", "Hecken", null], - ["071405004049", "Heinzenbach", null], - ["071405004050", "Henau", null], - ["071405004053", "Hirschfeld (Hunsrück)", null], - ["071405004062", "Kappel", null], - ["071405004067", "Kirchberg (Hunsrück), Stadt", null], - ["071405004071", "Kludenbach", null], - ["071405004081", "Laufersweiler", null], - ["071405004082", "Lautzenhausen", null], - ["071405004086", "Lindenschied", null], - ["071405004090", "Maitzborn", null], - ["071405004094", "Metzenhausen", null], - ["071405004105", "Nieder Kostenz", null], - ["071405004107", "Niedersohren", null], - ["071405004109", "Niederweiler", null], - ["071405004111", "Ober Kostenz", null], - ["071405004120", "Raversbeuren", null], - ["071405004122", "Reckershausen", null], - ["071405004128", "Rödelhausen", null], - ["071405004129", "Rödern", null], - ["071405004130", "Rohrbach", null], - ["071405004135", "Schlierschied", null], - ["071405004141", "Schwarzen", null], - ["071405004145", "Sohren", null], - ["071405004146", "Sohrschied", null], - ["071405004151", "Todenroth", null], - ["071405004154", "Unzenberg", null], - ["071405004159", "Wahlenau", null], - ["071405004163", "Womrath", null], - ["071405004164", "Woppenroth", null], - ["071405004165", "Würrich", null], - ["071405008002", "Altweidelbach", null], - ["071405008003", "Argenthal", null], - ["071405008008", "Belgweiler", null], - ["071405008011", "Benzweiler", null], - ["071405008012", "Bergenhausen", null], - ["071405008015", "Biebern", null], - ["071405008020", "Bubach", null], - ["071405008023", "Budenbach", null], - ["071405008027", "Dichtelbach", null], - ["071405008035", "Ellern (Hunsrück)", null], - ["071405008037", "Erbach", null], - ["071405008039", "Fronhofen", null], - ["071405008056", "Holzbach", null], - ["071405008058", "Horn", null], - ["071405008065", "Keidelheim", null], - ["071405008068", "Kisselbach", null], - ["071405008070", "Klosterkumbd", null], - ["071405008076", "Külz (Hunsrück)", null], - ["071405008077", "Kümbdchen", null], - ["071405008079", "Laubach", null], - ["071405008085", "Liebshausen", null], - ["071405008092", "Mengerschied", null], - ["071405008096", "Mörschbach", null], - ["071405008099", "Mutterschied", null], - ["071405008100", "Nannhausen", null], - ["071405008101", "Neuerkirch", null], - ["071405008106", "Niederkumbd", null], - ["071405008113", "Ohlweiler", null], - ["071405008115", "Oppertshausen", null], - ["071405008118", "Pleizenhausen", null], - ["071405008119", "Ravengiersburg", null], - ["071405008121", "Rayerschied", null], - ["071405008123", "Reich", null], - ["071405008125", "Rheinböllen, Stadt", null], - ["071405008126", "Riegenroth", null], - ["071405008127", "Riesweiler", null], - ["071405008134", "Sargenroth", null], - ["071405008138", "Schnorbach", null], - ["071405008139", "Schönborn", null], - ["071405008144", "Simmern/ Hunsrück, Stadt", null], - ["071405008148", "Steinbach", null], - ["071405008150", "Tiefenbach", null], - ["071405008158", "Wahlbach", null], - ["071405008166", "Wüschheim", null], - ["071405009005", "Badenhard", null], - ["071405009014", "Bickenbach", null], - ["071405009016", "Birkheim", null], - ["071405009025", "Damscheid", null], - ["071405009031", "Dörth", null], - ["071405009036", "Emmelshausen, Stadt", null], - ["071405009043", "Gondershausen", null], - ["071405009045", "Halsenbach", null], - ["071405009047", "Hausbay", null], - ["071405009060", "Hungenroth", null], - ["071405009063", "Karbach", null], - ["071405009075", "Kratzenburg", null], - ["071405009080", "Laudert", null], - ["071405009084", "Leiningen", null], - ["071405009087", "Lingerhahn", null], - ["071405009089", "Maisborn", null], - ["071405009093", "Mermuth", null], - ["071405009098", "Mühlpfad", null], - ["071405009102", "Ney", null], - ["071405009104", "Niederburg", null], - ["071405009108", "Niedert", null], - ["071405009110", "Norath", null], - ["071405009112", "Oberwesel, Stadt", null], - ["071405009116", "Perscheid", null], - ["071405009117", "Pfalzfeld", null], - ["071405009133", "Sankt Goar, Stadt", null], - ["071405009140", "Schwall", null], - ["071405009149", "Thörlingen", null], - ["071405009155", "Urbar", null], - ["071405009156", "Utzenhain", null], - ["071405009161", "Wiebelsheim", null], - ["071405009201", "Beulich", null], - ["071405009205", "Morshausen", null], - ["071410075075", "Lahnstein, Stadt", null], - ["071415003002", "Altendiez", null], - ["071415003005", "Aull", null], - ["071415003014", "Birlenbach", null], - ["071415003021", "Charlottenberg", null], - ["071415003022", "Cramberg", null], - ["071415003029", "Diez, Stadt", null], - ["071415003030", "Dörnberg", null], - ["071415003038", "Eppenrod", null], - ["071415003045", "Geilnau", null], - ["071415003049", "Gückingen", null], - ["071415003052", "Hambach", null], - ["071415003053", "Heistenbach", null], - ["071415003057", "Hirschberg", null], - ["071415003059", "Holzappel", null], - ["071415003061", "Holzheim", null], - ["071415003062", "Horhausen", null], - ["071415003064", "Isselbach", null], - ["071415003076", "Langenscheid", null], - ["071415003077", "Laurenburg", null], - ["071415003124", "Scheidt", null], - ["071415003130", "Steinsberg", null], - ["071415003133", "Wasenbach", null], - ["071415003503", "Balduinstein", null], - ["071415007009", "Berg", null], - ["071415007012", "Bettendorf", null], - ["071415007015", "Bogel", null], - ["071415007019", "Buch", null], - ["071415007035", "Ehr", null], - ["071415007037", "Endlichhofen", null], - ["071415007040", "Eschbach", null], - ["071415007047", "Gemmerich", null], - ["071415007055", "Himmighofen", null], - ["071415007060", "Holzhausen an der Haide", null], - ["071415007063", "Hunzel", null], - ["071415007067", "Kasdorf", null], - ["071415007070", "Kehlbach", null], - ["071415007078", "Lautert", null], - ["071415007080", "Lipporn", null], - ["071415007084", "Marienfels", null], - ["071415007085", "Miehlen", null], - ["071415007092", "Nastätten, Stadt", null], - ["071415007094", "Niederbachheim", null], - ["071415007097", "Niederwallmenach", null], - ["071415007100", "Oberbachheim", null], - ["071415007104", "Obertiefenbach", null], - ["071415007105", "Oberwallmenach", null], - ["071415007107", "Oelsberg", null], - ["071415007110", "Hainau", null], - ["071415007116", "Rettershain", null], - ["071415007120", "Ruppertshofen", null], - ["071415007131", "Strüth", null], - ["071415007134", "Weidenbach", null], - ["071415007137", "Welterod", null], - ["071415007140", "Winterwerb", null], - ["071415007502", "Diethardt", null], - ["071415009004", "Auel", null], - ["071415009016", "Bornich", null], - ["071415009023", "Dachsenhausen", null], - ["071415009024", "Dahlheim", null], - ["071415009031", "Dörscheid", null], - ["071415009042", "Filsen", null], - ["071415009066", "Kamp-Bornhofen", null], - ["071415009069", "Kaub, Stadt", null], - ["071415009072", "Kestert", null], - ["071415009079", "Lierschied", null], - ["071415009083", "Lykershausen", null], - ["071415009099", "Nochern", null], - ["071415009108", "Osterspai", null], - ["071415009109", "Patersberg", null], - ["071415009112", "Prath", null], - ["071415009114", "Reichenberg", null], - ["071415009115", "Reitzenhain", null], - ["071415009121", "Sankt Goarshausen, Loreleystadt, Stadt", null], - ["071415009122", "Sauerthal", null], - ["071415009136", "Weisel", null], - ["071415009138", "Weyer", null], - ["071415009501", "Braubach, Stadt", null], - ["071415010003", "Attenhausen", null], - ["071415010006", "Bad Ems, Stadt", null], - ["071415010008", "Becheln", null], - ["071415010025", "Dausenau", null], - ["071415010026", "Dessighofen", null], - ["071415010027", "Dienethal", null], - ["071415010033", "Dornholzhausen", null], - ["071415010041", "Fachbach", null], - ["071415010044", "Frücht", null], - ["071415010046", "Geisig", null], - ["071415010058", "Hömberg", null], - ["071415010071", "Kemmenau", null], - ["071415010082", "Lollschied", null], - ["071415010086", "Miellen", null], - ["071415010087", "Misselberg", null], - ["071415010091", "Nassau, Stadt", null], - ["071415010098", "Nievern", null], - ["071415010103", "Obernhof", null], - ["071415010106", "Oberwies", null], - ["071415010111", "Pohl", null], - ["071415010127", "Schweighausen", null], - ["071415010128", "Seelbach", null], - ["071415010129", "Singhofen", null], - ["071415010132", "Sulzbach", null], - ["071415010135", "Weinähr", null], - ["071415010139", "Winden", null], - ["071415010141", "Zimmerschied", null], - ["071415010201", "Arzbach", null], - ["071415011001", "Allendorf", null], - ["071415011010", "Berghausen", null], - ["071415011011", "Berndroth", null], - ["071415011013", "Biebrich", null], - ["071415011018", "Bremberg", null], - ["071415011020", "Burgschwalbach", null], - ["071415011032", "Dörsdorf", null], - ["071415011034", "Ebertshausen", null], - ["071415011036", "Eisighofen", null], - ["071415011039", "Ergeshausen", null], - ["071415011043", "Flacht", null], - ["071415011050", "Gutenacker", null], - ["071415011051", "Hahnstätten", null], - ["071415011054", "Herold", null], - ["071415011065", "Kaltenholzhausen", null], - ["071415011068", "Katzenelnbogen, Stadt", null], - ["071415011073", "Klingelbach", null], - ["071415011074", "Kördorf", null], - ["071415011081", "Lohrheim", null], - ["071415011088", "Mittelfischbach", null], - ["071415011089", "Mudershausen", null], - ["071415011093", "Netzbach", null], - ["071415011095", "Niederneisen", null], - ["071415011096", "Niedertiefenbach", null], - ["071415011101", "Oberfischbach", null], - ["071415011102", "Oberneisen", null], - ["071415011113", "Reckenroth", null], - ["071415011117", "Rettert", null], - ["071415011118", "Roth", null], - ["071415011125", "Schiesheim", null], - ["071415011126", "Schönborn", null], - ["071435001206", "Bad Marienberg (Westerwald), Stadt", null], - ["071435001211", "Bölsberg", null], - ["071435001216", "Dreisbach", null], - ["071435001222", "Fehl-Ritzhausen", null], - ["071435001227", "Großseifen", null], - ["071435001231", "Hahn bei Marienberg", null], - ["071435001234", "Hardt", null], - ["071435001243", "Hof", null], - ["071435001248", "Kirburg", null], - ["071435001253", "Langenbach bei Kirburg", null], - ["071435001255", "Lautzenbrücken", null], - ["071435001264", "Mörlen", null], - ["071435001270", "Neunkhausen", null], - ["071435001277", "Nisterau", null], - ["071435001279", "Nistertal", null], - ["071435001280", "Norken", null], - ["071435001297", "Stockhausen-Illfurth", null], - ["071435001300", "Unnau", null], - ["071435002202", "Alpenrod", null], - ["071435002204", "Astert", null], - ["071435002205", "Atzelgift", null], - ["071435002212", "Borod", null], - ["071435002215", "Dreifelden", null], - ["071435002223", "Gehlert", null], - ["071435002225", "Giesenhausen", null], - ["071435002229", "Hachenburg, Stadt", null], - ["071435002235", "Hattert", null], - ["071435002236", "Heimborn", null], - ["071435002240", "Heuzert", null], - ["071435002241", "Höchstenbach", null], - ["071435002250", "Kroppach", null], - ["071435002252", "Kundert", null], - ["071435002257", "Limbach", null], - ["071435002258", "Linden", null], - ["071435002259", "Lochum", null], - ["071435002260", "Luckenbach", null], - ["071435002261", "Marzhausen", null], - ["071435002262", "Merkelbach", null], - ["071435002265", "Mörsbach", null], - ["071435002267", "Mudenbach", null], - ["071435002268", "Mündersbach", null], - ["071435002269", "Müschenbach", null], - ["071435002276", "Nister", null], - ["071435002287", "Roßbach", null], - ["071435002294", "Steinebach an der Wied", null], - ["071435002296", "Stein-Wingert", null], - ["071435002299", "Streithausen", null], - ["071435002301", "Wahlrod", null], - ["071435002306", "Welkenbach", null], - ["071435002310", "Wied", null], - ["071435002313", "Winkelbach", null], - ["071435003030", "Hilgert", null], - ["071435003031", "Hillscheid", null], - ["071435003032", "Höhr-Grenzhausen, Stadt", null], - ["071435003040", "Kammerforst", null], - ["071435004005", "Boden", null], - ["071435004008", "Daubach", null], - ["071435004013", "Eitelborn", null], - ["071435004020", "Gackenbach", null], - ["071435004021", "Girod", null], - ["071435004023", "Görgeshausen", null], - ["071435004024", "Großholbach", null], - ["071435004026", "Heilberscheid", null], - ["071435004027", "Heiligenroth", null], - ["071435004033", "Holler", null], - ["071435004034", "Horbach", null], - ["071435004036", "Hübingen", null], - ["071435004039", "Kadenbach", null], - ["071435004048", "Montabaur, Stadt", null], - ["071435004051", "Nentershausen", null], - ["071435004052", "Neuhäusel", null], - ["071435004053", "Niederelbert", null], - ["071435004054", "Niedererbach", null], - ["071435004055", "Nomborn", null], - ["071435004057", "Oberelbert", null], - ["071435004065", "Ruppach-Goldhausen", null], - ["071435004071", "Simmern", null], - ["071435004072", "Stahlhofen", null], - ["071435004077", "Untershausen", null], - ["071435004079", "Welschneudorf", null], - ["071435005001", "Alsbach", null], - ["071435005006", "Breitenau", null], - ["071435005007", "Caan", null], - ["071435005009", "Deesen", null], - ["071435005038", "Hundsdorf", null], - ["071435005050", "Nauort", null], - ["071435005059", "Oberhaid", null], - ["071435005062", "Ransbach-Baumbach, Stadt", null], - ["071435005068", "Sessenbach", null], - ["071435005082", "Wirscheid", null], - ["071435005084", "Wittgert", null], - ["071435006214", "Bretthausen", null], - ["071435006218", "Elsoff (Westerwald)", null], - ["071435006237", "Hellenhahn-Schellenberg", null], - ["071435006244", "Homberg", null], - ["071435006245", "Hüblingen", null], - ["071435006246", "Irmtraut", null], - ["071435006256", "Liebenscheid", null], - ["071435006271", "Neunkirchen", null], - ["071435006272", "Neustadt/ Westerwald", null], - ["071435006274", "Niederroßbach", null], - ["071435006278", "Nister-Möhrendorf", null], - ["071435006282", "Oberrod", null], - ["071435006283", "Oberroßbach", null], - ["071435006285", "Rehe", null], - ["071435006286", "Rennerod, Stadt", null], - ["071435006291", "Salzburg", null], - ["071435006292", "Seck", null], - ["071435006295", "Stein-Neukirch", null], - ["071435006302", "Waigandshain", null], - ["071435006303", "Waldmühlen", null], - ["071435006309", "Westernohe", null], - ["071435006311", "Willingen", null], - ["071435006315", "Zehnhausen bei Rennerod", null], - ["071435007015", "Ellenhausen", null], - ["071435007018", "Freilingen", null], - ["071435007019", "Freirachdorf", null], - ["071435007022", "Goddert", null], - ["071435007025", "Hartenfels", null], - ["071435007029", "Herschbach", null], - ["071435007041", "Krümmel", null], - ["071435007044", "Marienrachdorf", null], - ["071435007045", "Maroth", null], - ["071435007046", "Maxsain", null], - ["071435007056", "Nordhofen", null], - ["071435007061", "Quirnbach", null], - ["071435007064", "Rückeroth", null], - ["071435007066", "Schenkelberg", null], - ["071435007067", "Selters (Westerwald), Stadt", null], - ["071435007069", "Sessenhausen", null], - ["071435007075", "Steinen", null], - ["071435007078", "Vielbach", null], - ["071435007085", "Wölferlingen", null], - ["071435007221", "Ewighausen", null], - ["071435007305", "Weidenhahn", null], - ["071435008011", "Dreikirchen", null], - ["071435008037", "Hundsangen", null], - ["071435008058", "Obererbach", null], - ["071435008074", "Steinefrenz", null], - ["071435008080", "Weroth", null], - ["071435008203", "Arnshöfen", null], - ["071435008208", "Berod bei Wallmerod", null], - ["071435008210", "Bilkheim", null], - ["071435008220", "Ettinghausen", null], - ["071435008232", "Hahn am See", null], - ["071435008239", "Herschbach (Oberwesterwald)", null], - ["071435008251", "Kuhnhöfen", null], - ["071435008263", "Meudt", null], - ["071435008266", "Molsberg", null], - ["071435008273", "Niederahr", null], - ["071435008281", "Oberahr", null], - ["071435008290", "Salz", null], - ["071435008304", "Wallmerod", null], - ["071435008316", "Zehnhausen bei Wallmerod", null], - ["071435008501", "Elbingen", null], - ["071435008502", "Mähren", null], - ["071435009200", "Ailertchen", null], - ["071435009207", "Bellingen", null], - ["071435009209", "Berzhahn", null], - ["071435009213", "Brandscheid", null], - ["071435009219", "Enspel", null], - ["071435009224", "Gemünden", null], - ["071435009226", "Girkenroth", null], - ["071435009228", "Guckheim", null], - ["071435009230", "Härtlingen", null], - ["071435009233", "Halbs", null], - ["071435009238", "Hergenroth", null], - ["071435009242", "Höhn", null], - ["071435009247", "Kaden", null], - ["071435009249", "Kölbingen", null], - ["071435009254", "Langenhahn", null], - ["071435009284", "Pottum", null], - ["071435009288", "Rotenhain", null], - ["071435009289", "Rothenbach", null], - ["071435009293", "Stahlhofen am Wiesensee", null], - ["071435009298", "Stockum-Püschen", null], - ["071435009307", "Weltersburg", null], - ["071435009308", "Westerburg, Stadt", null], - ["071435009312", "Willmenrod", null], - ["071435009314", "Winnen", null], - ["071435010003", "Bannberscheid", null], - ["071435010010", "Dernbach (Westerwald)", null], - ["071435010012", "Ebernhahn", null], - ["071435010028", "Helferskirchen", null], - ["071435010042", "Leuterod", null], - ["071435010047", "Mogendorf", null], - ["071435010049", "Moschheim", null], - ["071435010060", "Ötzingen", null], - ["071435010070", "Siershahn", null], - ["071435010073", "Staudt", null], - ["071435010081", "Wirges, Stadt", null], - ["071435010275", "Niedersayn", null], - ["072110000000", "Trier, Stadt", null], - ["072310134134", "Wittlich, Stadt", null], - ["072310502502", "Morbach", null], - ["072315001008", "Bernkastel-Kues, Stadt", null], - ["072315001012", "Brauneberg", null], - ["072315001016", "Burgen", null], - ["072315001030", "Erden", null], - ["072315001040", "Gornhausen", null], - ["072315001041", "Graach an der Mosel", null], - ["072315001056", "Hochscheid", null], - ["072315001066", "Kesten", null], - ["072315001070", "Kleinich", null], - ["072315001071", "Kommen", null], - ["072315001075", "Lieser", null], - ["072315001076", "Lösnich", null], - ["072315001077", "Longkamp", null], - ["072315001081", "Maring-Noviand", null], - ["072315001086", "Minheim", null], - ["072315001087", "Monzelfeld", null], - ["072315001090", "Mülheim an der Mosel", null], - ["072315001092", "Neumagen-Dhron", null], - ["072315001105", "Piesport", null], - ["072315001125", "Ürzig", null], - ["072315001126", "Veldenz", null], - ["072315001133", "Wintrich", null], - ["072315001136", "Zeltingen-Rachtig", null], - ["072315006006", "Berglicht", null], - ["072315006017", "Burtscheid", null], - ["072315006018", "Deuselbach", null], - ["072315006019", "Dhronecken", null], - ["072315006032", "Etgert", null], - ["072315006035", "Gielert", null], - ["072315006042", "Gräfendhron", null], - ["072315006054", "Hilscheid", null], - ["072315006058", "Horath", null], - ["072315006064", "Immert", null], - ["072315006078", "Lückenburg", null], - ["072315006079", "Malborn", null], - ["072315006083", "Merschbach", null], - ["072315006093", "Neunkirchen", null], - ["072315006112", "Rorodt", null], - ["072315006115", "Schönberg", null], - ["072315006122", "Talling", null], - ["072315006123", "Thalfang", null], - ["072315006202", "Breit", null], - ["072315006203", "Büdlich", null], - ["072315006204", "Heidenburg", null], - ["072315008001", "Altrich", null], - ["072315008003", "Arenrath", null], - ["072315008007", "Bergweiler", null], - ["072315008009", "Bettenfeld", null], - ["072315008010", "Binsfeld", null], - ["072315008013", "Bruch", null], - ["072315008021", "Dierfeld", null], - ["072315008022", "Dierscheid", null], - ["072315008023", "Dodenburg", null], - ["072315008024", "Dreis", null], - ["072315008025", "Eckfeld", null], - ["072315008026", "Eisenschmitt", null], - ["072315008031", "Esch", null], - ["072315008036", "Gipperath", null], - ["072315008037", "Gladbach", null], - ["072315008044", "Greimerath", null], - ["072315008046", "Großlittgen", null], - ["072315008049", "Hasborn", null], - ["072315008050", "Heckenmünster", null], - ["072315008051", "Heidweiler", null], - ["072315008053", "Hetzerath", null], - ["072315008062", "Hupperath", null], - ["072315008065", "Karl", null], - ["072315008069", "Klausen", null], - ["072315008074", "Laufeld", null], - ["072315008080", "Manderscheid, Stadt", null], - ["072315008082", "Meerfeld", null], - ["072315008085", "Minderlittgen", null], - ["072315008091", "Musweiler", null], - ["072315008095", "Niederöfflingen", null], - ["072315008096", "Niederscheidweiler", null], - ["072315008100", "Oberöfflingen", null], - ["072315008101", "Oberscheidweiler", null], - ["072315008103", "Osann-Monzel", null], - ["072315008104", "Pantenburg", null], - ["072315008107", "Platten", null], - ["072315008108", "Plein", null], - ["072315008111", "Rivenich", null], - ["072315008113", "Salmtal", null], - ["072315008114", "Schladt", null], - ["072315008116", "Schwarzenborn", null], - ["072315008117", "Sehlem", null], - ["072315008127", "Wallscheid", null], - ["072315008503", "Landscheid", null], - ["072315008504", "Niersbach", null], - ["072315009004", "Bausendorf", null], - ["072315009005", "Bengel", null], - ["072315009014", "Burg (Mosel)", null], - ["072315009020", "Diefenbach", null], - ["072315009029", "Enkirch", null], - ["072315009033", "Flußbach", null], - ["072315009057", "Hontheim", null], - ["072315009067", "Kinderbeuern", null], - ["072315009068", "Kinheim", null], - ["072315009072", "Kröv", null], - ["072315009110", "Reil", null], - ["072315009120", "Starkenburg", null], - ["072315009124", "Traben-Trarbach, Stadt", null], - ["072315009132", "Willwerscheid", null], - ["072315009206", "Lötzbeuren", null], - ["072315009501", "Irmenach", null], - ["072320018018", "Bitburg, Stadt", null], - ["072325001201", "Arzfeld", null], - ["072325001211", "Dackscheid", null], - ["072325001212", "Dahnen", null], - ["072325001213", "Daleiden", null], - ["072325001214", "Dasburg", null], - ["072325001217", "Eilscheid", null], - ["072325001220", "Eschfeld", null], - ["072325001221", "Euscheid", null], - ["072325001229", "Großkampenberg", null], - ["072325001233", "Hargarten", null], - ["072325001234", "Harspelt", null], - ["072325001240", "Herzfeld", null], - ["072325001245", "Irrhausen", null], - ["072325001246", "Jucken", null], - ["072325001247", "Kesfeld", null], - ["072325001248", "Kickeshausen", null], - ["072325001249", "Kinzenburg", null], - ["072325001253", "Krautscheid", null], - ["072325001254", "Lambertsberg", null], - ["072325001255", "Lascheid", null], - ["072325001258", "Lauperath", null], - ["072325001259", "Leidenborn", null], - ["072325001260", "Lichtenborn", null], - ["072325001261", "Lierfeld", null], - ["072325001262", "Lünebach", null], - ["072325001263", "Lützkampen", null], - ["072325001264", "Manderscheid", null], - ["072325001267", "Mauel", null], - ["072325001270", "Merlscheid", null], - ["072325001277", "Niederpierscheid", null], - ["072325001285", "Oberpierscheid", null], - ["072325001287", "Olmscheid", null], - ["072325001291", "Pintesfeld", null], - ["072325001293", "Plütscheid", null], - ["072325001294", "Preischeid", null], - ["072325001297", "Reiff", null], - ["072325001298", "Reipeldingen", null], - ["072325001301", "Roscheid", null], - ["072325001309", "Sengerich", null], - ["072325001310", "Sevenig (Our)", null], - ["072325001315", "Strickscheid", null], - ["072325001322", "Waxweiler", null], - ["072325001333", "Üttfeld", null], - ["072325005001", "Affler", null], - ["072325005002", "Alsdorf", null], - ["072325005003", "Altscheid", null], - ["072325005004", "Ammeldingen an der Our", null], - ["072325005005", "Ammeldingen bei Neuerburg", null], - ["072325005008", "Bauler", null], - ["072325005011", "Berkoth", null], - ["072325005012", "Berscheid", null], - ["072325005016", "Biesdorf", null], - ["072325005019", "Bollendorf", null], - ["072325005022", "Burg", null], - ["072325005025", "Dauwelshausen", null], - ["072325005028", "Echternacherbrück", null], - ["072325005031", "Emmelbaum", null], - ["072325005033", "Ernzen", null], - ["072325005037", "Ferschweiler", null], - ["072325005038", "Fischbach-Oberraden", null], - ["072325005040", "Geichlingen", null], - ["072325005041", "Gemünd", null], - ["072325005042", "Gentingen", null], - ["072325005047", "Heilbach", null], - ["072325005049", "Herbstmühle", null], - ["072325005053", "Holsthum", null], - ["072325005054", "Hommerdingen", null], - ["072325005056", "Hütten", null], - ["072325005059", "Hüttingen bei Lahr", null], - ["072325005063", "Irrel", null], - ["072325005064", "Karlshausen", null], - ["072325005065", "Kaschenbach", null], - ["072325005066", "Keppeshausen", null], - ["072325005067", "Körperich", null], - ["072325005068", "Koxhausen", null], - ["072325005069", "Kruchten", null], - ["072325005072", "Lahr", null], - ["072325005073", "Leimbach", null], - ["072325005078", "Menningen", null], - ["072325005080", "Mettendorf", null], - ["072325005082", "Minden", null], - ["072325005084", "Muxerath", null], - ["072325005085", "Nasingen", null], - ["072325005088", "Neuerburg, Stadt", null], - ["072325005089", "Niedergeckler", null], - ["072325005090", "Niederraden", null], - ["072325005093", "Niederweis", null], - ["072325005094", "Niehl", null], - ["072325005095", "Nusbaum", null], - ["072325005096", "Obergeckler", null], - ["072325005102", "Utscheid", null], - ["072325005103", "Peffingen", null], - ["072325005106", "Plascheid", null], - ["072325005108", "Prümzurlay", null], - ["072325005110", "Rodershausen", null], - ["072325005112", "Roth an der Our", null], - ["072325005114", "Schankweiler", null], - ["072325005116", "Scheitenkorb", null], - ["072325005117", "Scheuern", null], - ["072325005121", "Sevenig bei Neuerburg", null], - ["072325005122", "Sinspelt", null], - ["072325005127", "Übereisenbach", null], - ["072325005128", "Uppershausen", null], - ["072325005130", "Waldhof-Falkenstein", null], - ["072325005131", "Wallendorf", null], - ["072325005132", "Weidingen", null], - ["072325005138", "Zweifelscheid", null], - ["072325005218", "Eisenach", null], - ["072325005225", "Gilzem", null], - ["072325006202", "Auw bei Prüm", null], - ["072325006206", "Bleialf", null], - ["072325006207", "Brandscheid", null], - ["072325006208", "Buchet", null], - ["072325006209", "Büdesheim", null], - ["072325006216", "Dingdorf", null], - ["072325006222", "Feuerscheid", null], - ["072325006223", "Fleringen", null], - ["072325006224", "Giesdorf", null], - ["072325006226", "Weinsheim", null], - ["072325006227", "Gondenbrett", null], - ["072325006230", "Großlangenfeld", null], - ["072325006231", "Habscheid", null], - ["072325006236", "Heckhuscheid", null], - ["072325006238", "Heisdorf", null], - ["072325006250", "Kleinlangenfeld", null], - ["072325006256", "Lasel", null], - ["072325006265", "Masthorn", null], - ["072325006266", "Matzerath", null], - ["072325006271", "Mützenich", null], - ["072325006272", "Neuendorf", null], - ["072325006276", "Niederlauch", null], - ["072325006279", "Nimshuscheid", null], - ["072325006280", "Nimsreuland", null], - ["072325006283", "Oberlascheid", null], - ["072325006284", "Oberlauch", null], - ["072325006288", "Olzheim", null], - ["072325006290", "Orlenbach", null], - ["072325006292", "Pittenbach", null], - ["072325006295", "Pronsfeld", null], - ["072325006296", "Prüm, Stadt", null], - ["072325006300", "Rommersheim", null], - ["072325006302", "Roth bei Prüm", null], - ["072325006304", "Schönecken", null], - ["072325006305", "Schwirzheim", null], - ["072325006307", "Seiwerath", null], - ["072325006308", "Sellerich", null], - ["072325006318", "Wallersheim", null], - ["072325006320", "Watzerath", null], - ["072325006321", "Wawern", null], - ["072325006327", "Winringen", null], - ["072325006328", "Winterscheid", null], - ["072325006329", "Winterspelt", null], - ["072325006332", "Hersdorf", null], - ["072325007006", "Auw an der Kyll", null], - ["072325007010", "Beilingen", null], - ["072325007050", "Herforst", null], - ["072325007055", "Hosten", null], - ["072325007104", "Philippsheim", null], - ["072325007107", "Preist", null], - ["072325007123", "Speicher, Stadt", null], - ["072325007289", "Orenhofen", null], - ["072325007311", "Spangdahlem", null], - ["072325008007", "Badem", null], - ["072325008009", "Baustert", null], - ["072325008013", "Bettingen", null], - ["072325008014", "Bickendorf", null], - ["072325008015", "Biersdorf am See", null], - ["072325008017", "Birtlingen", null], - ["072325008020", "Brecht", null], - ["072325008024", "Dahlem", null], - ["072325008026", "Dockendorf", null], - ["072325008027", "Dudeldorf", null], - ["072325008029", "Echtershausen", null], - ["072325008030", "Ehlenz", null], - ["072325008032", "Enzen", null], - ["072325008034", "Eßlingen", null], - ["072325008035", "Etteldorf", null], - ["072325008036", "Feilsdorf", null], - ["072325008039", "Fließem", null], - ["072325008043", "Gindorf", null], - ["072325008044", "Gondorf", null], - ["072325008045", "Halsdorf", null], - ["072325008046", "Hamm", null], - ["072325008048", "Heilenbach", null], - ["072325008057", "Hütterscheid", null], - ["072325008058", "Hüttingen an der Kyll", null], - ["072325008060", "Idenheim", null], - ["072325008061", "Idesheim", null], - ["072325008062", "Ingendorf", null], - ["072325008070", "Kyllburg, Stadt", null], - ["072325008071", "Kyllburgweiler", null], - ["072325008074", "Ließem", null], - ["072325008075", "Malberg", null], - ["072325008076", "Malbergweich", null], - ["072325008077", "Meckel", null], - ["072325008079", "Messerich", null], - ["072325008081", "Metterich", null], - ["072325008083", "Mülbach", null], - ["072325008086", "Nattenheim", null], - ["072325008087", "Neidenbach", null], - ["072325008091", "Niederstedem", null], - ["072325008092", "Niederweiler", null], - ["072325008097", "Oberstedem", null], - ["072325008098", "Oberweiler", null], - ["072325008099", "Oberweis", null], - ["072325008100", "Olsdorf", null], - ["072325008101", "Orsfeld", null], - ["072325008105", "Pickließem", null], - ["072325008109", "Rittersdorf", null], - ["072325008111", "Röhl", null], - ["072325008113", "Sankt Thomas", null], - ["072325008115", "Scharfbillig", null], - ["072325008118", "Schleid", null], - ["072325008119", "Seffern", null], - ["072325008120", "Sefferweich", null], - ["072325008124", "Stockem", null], - ["072325008125", "Sülm", null], - ["072325008126", "Trimport", null], - ["072325008129", "Usch", null], - ["072325008133", "Wettlingen", null], - ["072325008134", "Wiersdorf", null], - ["072325008135", "Wilsecker", null], - ["072325008137", "Wolsfeld", null], - ["072325008203", "Balesfeld", null], - ["072325008210", "Burbach", null], - ["072325008228", "Gransdorf", null], - ["072325008273", "Neuheilenbach", null], - ["072325008282", "Oberkail", null], - ["072325008306", "Seinsfeld", null], - ["072325008313", "Steinborn", null], - ["072325008331", "Zendscheid", null], - ["072325008501", "Wißmannsdorf", null], - ["072325008502", "Brimingen", null], - ["072335001006", "Betteldorf", null], - ["072335001008", "Bleckhausen", null], - ["072335001011", "Brockscheid", null], - ["072335001014", "Darscheid", null], - ["072335001016", "Demerath", null], - ["072335001017", "Deudesfeld", null], - ["072335001018", "Dockweiler", null], - ["072335001020", "Dreis-Brück", null], - ["072335001021", "Ellscheid", null], - ["072335001025", "Gefell", null], - ["072335001027", "Gillenfeld", null], - ["072335001030", "Hinterweiler", null], - ["072335001031", "Hörscheid", null], - ["072335001034", "Immerath", null], - ["072335001039", "Kirchweiler", null], - ["072335001040", "Kradenbach", null], - ["072335001042", "Mehren", null], - ["072335001043", "Meisburg", null], - ["072335001046", "Mückeln", null], - ["072335001049", "Nerdlen", null], - ["072335001052", "Niederstadtfeld", null], - ["072335001055", "Oberstadtfeld", null], - ["072335001061", "Sarmersbach", null], - ["072335001062", "Saxler", null], - ["072335001063", "Schalkenmehren", null], - ["072335001064", "Schönbach", null], - ["072335001065", "Schutz", null], - ["072335001067", "Steineberg", null], - ["072335001068", "Steiningen", null], - ["072335001070", "Strohn", null], - ["072335001071", "Strotzbüsch", null], - ["072335001074", "Udler", null], - ["072335001075", "Üdersdorf", null], - ["072335001077", "Utzerath", null], - ["072335001079", "Wallenborn", null], - ["072335001081", "Weidenbach", null], - ["072335001084", "Winkel (Eifel)", null], - ["072335001501", "Daun, Stadt", null], - ["072335004003", "Beinhausen", null], - ["072335004010", "Boxberg", null], - ["072335004032", "Hörschhausen", null], - ["072335004037", "Katzwinkel", null], - ["072335004048", "Neichen", null], - ["072335004201", "Arbach", null], - ["072335004202", "Bereborn", null], - ["072335004203", "Berenbach", null], - ["072335004205", "Bodenbach", null], - ["072335004206", "Bongard", null], - ["072335004207", "Borler", null], - ["072335004208", "Brücktal", null], - ["072335004210", "Drees", null], - ["072335004212", "Gelenberg", null], - ["072335004213", "Gunderath", null], - ["072335004215", "Höchstberg", null], - ["072335004216", "Horperath", null], - ["072335004217", "Kaperich", null], - ["072335004218", "Kelberg", null], - ["072335004220", "Kirsbach", null], - ["072335004221", "Kötterichen", null], - ["072335004222", "Kolverath", null], - ["072335004224", "Lirstal", null], - ["072335004225", "Mannebach", null], - ["072335004226", "Mosbruch", null], - ["072335004228", "Nitz", null], - ["072335004230", "Oberelz", null], - ["072335004233", "Reimerath", null], - ["072335004234", "Retterath", null], - ["072335004236", "Sassen", null], - ["072335004242", "Uersfeld", null], - ["072335004243", "Ueß", null], - ["072335004244", "Welcherath", null], - ["072335006002", "Basberg", null], - ["072335006004", "Berlingen", null], - ["072335006005", "Berndorf", null], - ["072335006007", "Birgel", null], - ["072335006019", "Dohm-Lammersdorf", null], - ["072335006022", "Esch", null], - ["072335006023", "Feusdorf", null], - ["072335006026", "Gerolstein, Stadt", null], - ["072335006028", "Gönnersdorf", null], - ["072335006029", "Hillesheim, Stadt", null], - ["072335006033", "Hohenfels-Essingen", null], - ["072335006035", "Jünkerath", null], - ["072335006036", "Kalenborn-Scheuern", null], - ["072335006038", "Kerpen (Eifel)", null], - ["072335006041", "Lissendorf", null], - ["072335006050", "Neroth", null], - ["072335006053", "Oberbettingen", null], - ["072335006054", "Oberehe-Stroheich", null], - ["072335006056", "Pelm", null], - ["072335006058", "Rockeskyll", null], - ["072335006060", "Salm", null], - ["072335006076", "Üxheim", null], - ["072335006080", "Walsdorf", null], - ["072335006083", "Wiesbaum", null], - ["072335006204", "Birresborn", null], - ["072335006209", "Densborn", null], - ["072335006211", "Duppach", null], - ["072335006214", "Hallschlag", null], - ["072335006219", "Kerschenbach", null], - ["072335006223", "Kopp", null], - ["072335006227", "Mürlenbach", null], - ["072335006229", "Nohn", null], - ["072335006232", "Ormont", null], - ["072335006235", "Reuth", null], - ["072335006237", "Scheid", null], - ["072335006239", "Schüller", null], - ["072335006240", "Stadtkyll", null], - ["072335006241", "Steffeln", null], - ["072355001005", "Bescheid", null], - ["072355001008", "Beuren (Hochwald)", null], - ["072355001014", "Damflos", null], - ["072355001030", "Geisfeld", null], - ["072355001035", "Grimburg", null], - ["072355001036", "Gusenburg", null], - ["072355001045", "Hermeskeil, Stadt", null], - ["072355001047", "Hinzert-Pölert", null], - ["072355001092", "Naurath (Wald)", null], - ["072355001093", "Neuhütten", null], - ["072355001112", "Rascheid", null], - ["072355001114", "Reinsfeld", null], - ["072355001153", "Züsch", null], - ["072355003055", "Kanzem", null], - ["072355003068", "Konz, Stadt", null], - ["072355003095", "Nittel", null], - ["072355003096", "Oberbillig", null], - ["072355003101", "Onsdorf", null], - ["072355003106", "Pellingen", null], - ["072355003132", "Tawern", null], - ["072355003133", "Temmels", null], - ["072355003143", "Wasserliesch", null], - ["072355003144", "Wawern", null], - ["072355003146", "Wellen", null], - ["072355003148", "Wiltingen", null], - ["072355004010", "Bonerath", null], - ["072355004021", "Farschweiler", null], - ["072355004037", "Gusterath", null], - ["072355004038", "Gutweiler", null], - ["072355004044", "Herl", null], - ["072355004046", "Hinzenburg", null], - ["072355004050", "Holzerath", null], - ["072355004056", "Kasel", null], - ["072355004070", "Korlingen", null], - ["072355004080", "Lorscheid", null], - ["072355004085", "Mertesdorf", null], - ["072355004090", "Morscheid", null], - ["072355004100", "Ollmuth", null], - ["072355004103", "Osburg", null], - ["072355004107", "Pluwig", null], - ["072355004116", "Riveris", null], - ["072355004124", "Schöndorf", null], - ["072355004129", "Sommerau", null], - ["072355004135", "Thomm", null], - ["072355004141", "Waldrach", null], - ["072355006004", "Bekond", null], - ["072355006015", "Detzem", null], - ["072355006019", "Ensch", null], - ["072355006022", "Fell", null], - ["072355006026", "Föhren", null], - ["072355006060", "Kenn", null], - ["072355006063", "Klüsserath", null], - ["072355006067", "Köwerich", null], - ["072355006074", "Leiwen", null], - ["072355006077", "Longen", null], - ["072355006078", "Longuich", null], - ["072355006083", "Mehring", null], - ["072355006091", "Naurath (Eifel)", null], - ["072355006108", "Pölich", null], - ["072355006115", "Riol", null], - ["072355006120", "Schleich", null], - ["072355006125", "Schweich, Stadt", null], - ["072355006134", "Thörnich", null], - ["072355006207", "Trittenheim", null], - ["072355007001", "Aach", null], - ["072355007027", "Franzenheim", null], - ["072355007048", "Hockweiler", null], - ["072355007051", "Igel", null], - ["072355007069", "Kordel", null], - ["072355007073", "Langsur", null], - ["072355007094", "Newel", null], - ["072355007111", "Ralingen", null], - ["072355007137", "Trierweiler", null], - ["072355007151", "Zemmer", null], - ["072355007501", "Welschbillig", null], - ["072355008002", "Ayl", null], - ["072355008003", "Baldringen", null], - ["072355008025", "Fisch", null], - ["072355008028", "Freudenburg", null], - ["072355008033", "Greimerath", null], - ["072355008040", "Heddert", null], - ["072355008043", "Hentern", null], - ["072355008052", "Irsch", null], - ["072355008057", "Kastel-Staadt", null], - ["072355008058", "Kell am See", null], - ["072355008062", "Kirf", null], - ["072355008072", "Lampaden", null], - ["072355008081", "Mandern", null], - ["072355008082", "Mannebach", null], - ["072355008098", "Ockfen", null], - ["072355008104", "Palzem", null], - ["072355008105", "Paschel", null], - ["072355008118", "Saarburg, Stadt", null], - ["072355008119", "Schillingen", null], - ["072355008122", "Schoden", null], - ["072355008123", "Schömerich", null], - ["072355008126", "Serrig", null], - ["072355008131", "Taben-Rodt", null], - ["072355008136", "Trassem", null], - ["072355008140", "Vierherrenborn", null], - ["072355008142", "Waldweiler", null], - ["072355008149", "Wincheringen", null], - ["072355008152", "Zerf", null], - ["072355008154", "Merzkirchen", null], - ["073110000000", "Frankenthal (Pfalz), Stadt", null], - ["073120000000", "Kaiserslautern, Stadt", null], - ["073130000000", "Landau in der Pfalz, Stadt", null], - ["073140000000", "Ludwigshafen am Rhein, Stadt", null], - ["073150000000", "Mainz, Stadt", null], - ["073160000000", "Neustadt an der Weinstraße, Stadt", null], - ["073170000000", "Pirmasens, Stadt", null], - ["073180000000", "Speyer, Stadt", null], - ["073190000000", "Worms, Stadt", null], - ["073200000000", "Zweibrücken, Stadt", null], - ["073310003003", "Alzey, Stadt", null], - ["073315001001", "Albig", null], - ["073315001005", "Bechenheim", null], - ["073315001007", "Bechtolsheim", null], - ["073315001008", "Bermersheim vor der Höhe", null], - ["073315001010", "Biebelnheim", null], - ["073315001012", "Bornheim", null], - ["073315001014", "Dintesheim", null], - ["073315001020", "Eppelsheim", null], - ["073315001021", "Erbes-Büdesheim", null], - ["073315001022", "Esselborn", null], - ["073315001024", "Flomborn", null], - ["073315001025", "Flonheim", null], - ["073315001026", "Framersheim", null], - ["073315001027", "Freimersheim", null], - ["073315001031", "Gau-Heppenheim", null], - ["073315001032", "Gau-Odernheim", null], - ["073315001042", "Kettenheim", null], - ["073315001043", "Lonsheim", null], - ["073315001044", "Mauchenheim", null], - ["073315001050", "Nack", null], - ["073315001051", "Nieder-Wiesen", null], - ["073315001052", "Ober-Flörsheim", null], - ["073315001053", "Offenheim", null], - ["073315001067", "Wahlheim", null], - ["073315002002", "Alsheim", null], - ["073315002018", "Eich", null], - ["073315002034", "Gimbsheim", null], - ["073315002038", "Hamm am Rhein", null], - ["073315002045", "Mettenheim", null], - ["073315003023", "Flörsheim-Dalsheim", null], - ["073315003041", "Hohen-Sülzen", null], - ["073315003046", "Mölsheim", null], - ["073315003047", "Mörstadt", null], - ["073315003048", "Monsheim", null], - ["073315003054", "Offstein", null], - ["073315003066", "Wachenheim", null], - ["073315005017", "Eckelsheim", null], - ["073315005030", "Gau-Bickelheim", null], - ["073315005035", "Gumbsheim", null], - ["073315005060", "Siefersheim", null], - ["073315005062", "Stein-Bockenheim", null], - ["073315005070", "Wendelsheim", null], - ["073315005072", "Wöllstein", null], - ["073315005075", "Wonsheim", null], - ["073315006004", "Armsheim", null], - ["073315006019", "Ensheim", null], - ["073315006029", "Gabsheim", null], - ["073315006033", "Gau-Weinheim", null], - ["073315006056", "Partenheim", null], - ["073315006058", "Saulheim", null], - ["073315006059", "Schornsheim", null], - ["073315006061", "Spiesheim", null], - ["073315006063", "Sulzheim", null], - ["073315006064", "Udenheim", null], - ["073315006065", "Vendersheim", null], - ["073315006068", "Wallertheim", null], - ["073315006073", "Wörrstadt, Stadt", null], - ["073315007006", "Bechtheim", null], - ["073315007009", "Bermersheim", null], - ["073315007011", "Hochborn", null], - ["073315007015", "Dittelsheim-Heßloch", null], - ["073315007028", "Frettenheim", null], - ["073315007036", "Gundersheim", null], - ["073315007037", "Gundheim", null], - ["073315007039", "Hangen-Weisheim", null], - ["073315007049", "Monzernheim", null], - ["073315007055", "Osthofen, Stadt", null], - ["073315007071", "Westhofen", null], - ["073320002002", "Bad Dürkheim, Stadt", null], - ["073320024024", "Grünstadt, Stadt", null], - ["073320025025", "Haßloch", null], - ["073325001009", "Deidesheim, Stadt", null], - ["073325001017", "Forst an der Weinstraße", null], - ["073325001035", "Meckenheim", null], - ["073325001039", "Niederkirchen bei Deidesheim", null], - ["073325001043", "Ruppertsberg", null], - ["073325002005", "Bobenheim am Berg", null], - ["073325002008", "Dackenheim", null], - ["073325002015", "Erpolzheim", null], - ["073325002019", "Freinsheim, Stadt", null], - ["073325002026", "Herxheim am Berg", null], - ["073325002028", "Kallstadt", null], - ["073325002049", "Weisenheim am Berg", null], - ["073325002050", "Weisenheim am Sand", null], - ["073325005014", "Elmstein", null], - ["073325005016", "Esthal", null], - ["073325005018", "Frankeneck", null], - ["073325005032", "Lambrecht (Pfalz), Stadt", null], - ["073325005034", "Lindenberg", null], - ["073325005037", "Neidenfels", null], - ["073325005048", "Weidenthal", null], - ["073325006013", "Ellerstadt", null], - ["073325006020", "Friedelsheim", null], - ["073325006022", "Gönnheim", null], - ["073325006046", "Wachenheim an der Weinstraße, Stadt", null], - ["073325007001", "Altleiningen", null], - ["073325007003", "Battenberg (Pfalz)", null], - ["073325007004", "Bissersheim", null], - ["073325007006", "Bockenheim an der Weinstraße", null], - ["073325007007", "Carlsberg", null], - ["073325007010", "Dirmstein", null], - ["073325007012", "Ebertsheim", null], - ["073325007021", "Gerolsheim", null], - ["073325007023", "Großkarlbach", null], - ["073325007027", "Hettenleidelheim", null], - ["073325007029", "Kindenheim", null], - ["073325007030", "Kirchheim an der Weinstraße", null], - ["073325007031", "Kleinkarlbach", null], - ["073325007033", "Laumersheim", null], - ["073325007036", "Mertesheim", null], - ["073325007038", "Neuleiningen", null], - ["073325007040", "Obersülzen", null], - ["073325007041", "Obrigheim (Pfalz)", null], - ["073325007042", "Quirnheim", null], - ["073325007044", "Tiefenthal", null], - ["073325007047", "Wattenheim", null], - ["073335002019", "Eisenberg (Pfalz), Stadt", null], - ["073335002038", "Kerzenheim", null], - ["073335002060", "Ramsen", null], - ["073335003001", "Albisheim (Pfrimm)", null], - ["073335003006", "Biedesheim", null], - ["073335003012", "Bubenheim", null], - ["073335003017", "Dreisen", null], - ["073335003018", "Einselthum", null], - ["073335003026", "Göllheim", null], - ["073335003032", "Immesheim", null], - ["073335003041", "Lautersheim", null], - ["073335003058", "Ottersheim", null], - ["073335003064", "Rüssingen", null], - ["073335003074", "Standenbühl", null], - ["073335003081", "Weitersweiler", null], - ["073335003501", "Zellertal", null], - ["073335004005", "Bennhausen", null], - ["073335004007", "Bischheim", null], - ["073335004010", "Bolanden", null], - ["073335004013", "Dannenfels", null], - ["073335004022", "Gauersheim", null], - ["073335004031", "Ilbesheim", null], - ["073335004035", "Jakobsweiler", null], - ["073335004039", "Kirchheimbolanden, Stadt", null], - ["073335004040", "Kriegsfeld", null], - ["073335004045", "Marnheim", null], - ["073335004046", "Mörsfeld", null], - ["073335004047", "Morschheim", null], - ["073335004056", "Oberwiesen", null], - ["073335004057", "Orbis", null], - ["073335004062", "Rittersheim", null], - ["073335004076", "Stetten", null], - ["073335006009", "Börrstadt", null], - ["073335006011", "Breunigweiler", null], - ["073335006020", "Falkenstein", null], - ["073335006027", "Gonbach", null], - ["073335006030", "Höringen", null], - ["073335006033", "Imsbach", null], - ["073335006042", "Lohnsfeld", null], - ["073335006048", "Münchweiler an der Alsenz", null], - ["073335006069", "Schweisweiler", null], - ["073335006071", "Sippersfeld", null], - ["073335006075", "Steinbach am Donnersberg", null], - ["073335006080", "Wartenberg-Rohrbach", null], - ["073335006503", "Winnweiler", null], - ["073335007003", "Alsenz", null], - ["073335007004", "Bayerfeld-Steckweiler", null], - ["073335007008", "Bisterschied", null], - ["073335007014", "Dielkirchen", null], - ["073335007016", "Dörrmoschel", null], - ["073335007021", "Finkenbach-Gersweiler", null], - ["073335007023", "Gaugrehweiler", null], - ["073335007024", "Gehrweiler", null], - ["073335007025", "Gerbach", null], - ["073335007028", "Gundersweiler", null], - ["073335007034", "Imsweiler", null], - ["073335007036", "Kalkofen", null], - ["073335007037", "Katzenbach", null], - ["073335007043", "Mannweiler-Cölln", null], - ["073335007049", "Münsterappel", null], - ["073335007050", "Niederhausen an der Appel", null], - ["073335007051", "Niedermoschel", null], - ["073335007053", "Oberhausen an der Appel", null], - ["073335007054", "Obermoschel, Stadt", null], - ["073335007055", "Oberndorf", null], - ["073335007061", "Ransweiler", null], - ["073335007065", "Ruppertsecken", null], - ["073335007066", "Sankt Alban", null], - ["073335007067", "Schiersfeld", null], - ["073335007068", "Schönborn", null], - ["073335007072", "Sitters", null], - ["073335007073", "Stahlberg", null], - ["073335007077", "Teschenmoschel", null], - ["073335007078", "Unkenbach", null], - ["073335007079", "Waldgrehweiler", null], - ["073335007083", "Winterborn", null], - ["073335007084", "Würzweiler", null], - ["073335007201", "Rathskirchen", null], - ["073335007202", "Reichsthal", null], - ["073335007203", "Seelen", null], - ["073335007502", "Rockenhausen, Stadt", null], - ["073340007007", "Germersheim, Stadt", null], - ["073340501501", "Wörth am Rhein, Stadt", null], - ["073345001001", "Bellheim", null], - ["073345001014", "Knittelsheim", null], - ["073345001023", "Ottersheim bei Landau", null], - ["073345001036", "Zeiskam", null], - ["073345002002", "Berg (Pfalz)", null], - ["073345002008", "Hagenbach, Stadt", null], - ["073345002021", "Neuburg am Rhein", null], - ["073345002027", "Scheibenhardt", null], - ["073345003009", "Hatzenbühl", null], - ["073345003012", "Jockgrim", null], - ["073345003022", "Neupotz", null], - ["073345003024", "Rheinzabern", null], - ["073345004004", "Erlenbach bei Kandel", null], - ["073345004005", "Freckenfeld", null], - ["073345004013", "Kandel, Stadt", null], - ["073345004020", "Minfeld", null], - ["073345004030", "Steinweiler", null], - ["073345004031", "Vollmersweiler", null], - ["073345004034", "Winden", null], - ["073345005006", "Freisbach", null], - ["073345005017", "Lingenfeld", null], - ["073345005018", "Lustadt", null], - ["073345005028", "Schwegenheim", null], - ["073345005032", "Weingarten (Pfalz)", null], - ["073345005033", "Westheim (Pfalz)", null], - ["073345006011", "Hördt", null], - ["073345006015", "Kuhardt", null], - ["073345006016", "Leimersheim", null], - ["073345006025", "Rülzheim", null], - ["073355001003", "Bruchmühlbach-Miesau", null], - ["073355001011", "Gerhardsbrunn", null], - ["073355001201", "Lambsborn", null], - ["073355001202", "Langwieden", null], - ["073355001203", "Martinshöhe", null], - ["073355002004", "Enkenbach-Alsenborn", null], - ["073355002007", "Fischbach", null], - ["073355002010", "Frankenstein", null], - ["073355002015", "Hochspeyer", null], - ["073355002026", "Mehlingen", null], - ["073355002028", "Neuhemsbach", null], - ["073355002048", "Waldleiningen", null], - ["073355002205", "Sembach", null], - ["073355008016", "Hütschenhausen", null], - ["073355008020", "Kottweiler-Schwanden", null], - ["073355008030", "Niedermohr", null], - ["073355008038", "Ramstein-Miesenbach, Stadt", null], - ["073355008044", "Steinwenden", null], - ["073355009005", "Erzenhausen", null], - ["073355009006", "Eulenbis", null], - ["073355009019", "Kollweiler", null], - ["073355009024", "Mackenbach", null], - ["073355009040", "Rodenbach", null], - ["073355009043", "Schwedelbach", null], - ["073355009049", "Weilerbach", null], - ["073355009501", "Reichenbach-Steegen", null], - ["073355010009", "Frankelbach", null], - ["073355010013", "Heiligenmoschel", null], - ["073355010014", "Hirschhorn/ Pfalz", null], - ["073355010017", "Katzweiler", null], - ["073355010025", "Mehlbach", null], - ["073355010029", "Niederkirchen", null], - ["073355010033", "Olsbrücken", null], - ["073355010034", "Otterbach", null], - ["073355010035", "Otterberg, Stadt", null], - ["073355010041", "Schallodenbach", null], - ["073355010042", "Schneckenhausen", null], - ["073355010046", "Sulzbachtal", null], - ["073355011002", "Bann", null], - ["073355011012", "Hauptstuhl", null], - ["073355011018", "Kindsbach", null], - ["073355011021", "Krickenbach", null], - ["073355011022", "Landstuhl, Sickingenstadt, Stadt", null], - ["073355011023", "Linden", null], - ["073355011027", "Mittelbrunn", null], - ["073355011031", "Oberarnbach", null], - ["073355011037", "Queidersbach", null], - ["073355011045", "Stelzenberg", null], - ["073355011047", "Trippstadt", null], - ["073355011204", "Schopp", null], - ["073365008001", "Adenbach", null], - ["073365008005", "Aschbach", null], - ["073365008012", "Buborn", null], - ["073365008013", "Cronenberg", null], - ["073365008014", "Deimberg", null], - ["073365008019", "Einöllen", null], - ["073365008023", "Eßweiler", null], - ["073365008029", "Ginsweiler", null], - ["073365008030", "Glanbrücken", null], - ["073365008033", "Grumbach", null], - ["073365008035", "Hausweiler", null], - ["073365008036", "Hefersweiler", null], - ["073365008038", "Heinzenhausen", null], - ["073365008040", "Herren-Sulzbach", null], - ["073365008042", "Hinzweiler", null], - ["073365008043", "Hohenöllen", null], - ["073365008044", "Homberg", null], - ["073365008045", "Hoppstädten", null], - ["073365008048", "Jettenbach", null], - ["073365008049", "Kappeln", null], - ["073365008050", "Kirrweiler", null], - ["073365008053", "Kreimbach-Kaulbach", null], - ["073365008057", "Langweiler", null], - ["073365008058", "Lauterecken, Stadt", null], - ["073365008060", "Lohnweiler", null], - ["073365008061", "Medard", null], - ["073365008062", "Merzweiler", null], - ["073365008065", "Nerzweiler", null], - ["073365008069", "Nußbach", null], - ["073365008072", "Oberweiler im Tal", null], - ["073365008073", "Oberweiler-Tiefenbach", null], - ["073365008074", "Odenbach", null], - ["073365008075", "Offenbach-Hundheim", null], - ["073365008085", "Reipoltskirchen", null], - ["073365008086", "Relsberg", null], - ["073365008087", "Rothselberg", null], - ["073365008090", "Rutsweiler an der Lauter", null], - ["073365008095", "Sankt Julian", null], - ["073365008100", "Unterjeckenbach", null], - ["073365008104", "Wiesweiler", null], - ["073365008105", "Wolfstein, Stadt", null], - ["073365009004", "Altenkirchen", null], - ["073365009008", "Börsborn", null], - ["073365009010", "Breitenbach", null], - ["073365009011", "Brücken (Pfalz)", null], - ["073365009016", "Dittweiler", null], - ["073365009017", "Dunzweiler", null], - ["073365009027", "Frohnhofen", null], - ["073365009031", "Glan-Münchweiler", null], - ["073365009032", "Gries", null], - ["073365009037", "Henschtal", null], - ["073365009041", "Herschweiler-Pettersheim", null], - ["073365009047", "Hüffler", null], - ["073365009054", "Krottelbach", null], - ["073365009056", "Langenbach", null], - ["073365009064", "Nanzdietschweiler", null], - ["073365009076", "Ohmbach", null], - ["073365009082", "Rehweiler", null], - ["073365009092", "Schönenberg-Kübelberg", null], - ["073365009096", "Steinbach am Glan", null], - ["073365009101", "Wahnwegen", null], - ["073365009102", "Waldmohr, Stadt", null], - ["073365009107", "Matzenbach", null], - ["073365009501", "Quirnbach/ Pfalz", null], - ["073365010002", "Albessen", null], - ["073365010003", "Altenglan", null], - ["073365010006", "Blaubach", null], - ["073365010009", "Bosenbach", null], - ["073365010015", "Dennweiler-Frohnbach", null], - ["073365010018", "Ehweiler", null], - ["073365010021", "Elzweiler", null], - ["073365010022", "Erdesbach", null], - ["073365010024", "Etschberg", null], - ["073365010025", "Föckelberg", null], - ["073365010034", "Haschbach am Remigiusberg", null], - ["073365010039", "Herchweiler", null], - ["073365010046", "Horschbach", null], - ["073365010051", "Körborn", null], - ["073365010052", "Konken", null], - ["073365010055", "Kusel, Stadt", null], - ["073365010066", "Neunkirchen am Potzberg", null], - ["073365010067", "Niederalben", null], - ["073365010068", "Niederstaufenbach", null], - ["073365010070", "Oberalben", null], - ["073365010071", "Oberstaufenbach", null], - ["073365010077", "Pfeffelbach", null], - ["073365010079", "Rammelsbach", null], - ["073365010081", "Rathsweiler", null], - ["073365010084", "Reichweiler", null], - ["073365010088", "Ruthweiler", null], - ["073365010089", "Rutsweiler am Glan", null], - ["073365010091", "Schellweiler", null], - ["073365010094", "Selchenbach", null], - ["073365010097", "Thallichtenberg", null], - ["073365010098", "Theisbergstegen", null], - ["073365010099", "Ulmet", null], - ["073365010103", "Welchweiler", null], - ["073365010106", "Bedesbach", null], - ["073375001001", "Albersweiler", null], - ["073375001017", "Dernbach", null], - ["073375001024", "Eußerthal", null], - ["073375001033", "Gossersweiler-Stein", null], - ["073375001054", "Münchweiler am Klingbach", null], - ["073375001064", "Ramberg", null], - ["073375001067", "Rinnthal", null], - ["073375001074", "Silz", null], - ["073375001078", "Völkersweiler", null], - ["073375001080", "Waldhambach", null], - ["073375001081", "Waldrohrbach", null], - ["073375001083", "Wernersberg", null], - ["073375001501", "Annweiler am Trifels, Stadt", null], - ["073375002005", "Bad Bergzabern, Stadt", null], - ["073375002006", "Barbelroth", null], - ["073375002008", "Birkenhördt", null], - ["073375002013", "Böllenborn", null], - ["073375002018", "Dierbach", null], - ["073375002019", "Dörrenbach", null], - ["073375002029", "Gleiszellen-Gleishorbach", null], - ["073375002037", "Hergersweiler", null], - ["073375002045", "Kapellen-Drusweiler", null], - ["073375002046", "Kapsweyer", null], - ["073375002049", "Klingenmünster", null], - ["073375002055", "Niederhorbach", null], - ["073375002056", "Niederotterbach", null], - ["073375002058", "Oberhausen", null], - ["073375002059", "Oberotterbach", null], - ["073375002060", "Oberschlettenbach", null], - ["073375002062", "Pleisweiler-Oberhofen", null], - ["073375002071", "Schweigen-Rechtenbach", null], - ["073375002072", "Schweighofen", null], - ["073375002076", "Steinfeld", null], - ["073375002079", "Vorderweidenthal", null], - ["073375003002", "Altdorf", null], - ["073375003011", "Böbingen", null], - ["073375003015", "Burrweiler", null], - ["073375003020", "Edenkoben, Stadt", null], - ["073375003021", "Edesheim", null], - ["073375003025", "Flemlingen", null], - ["073375003027", "Freimersheim (Pfalz)", null], - ["073375003028", "Gleisweiler", null], - ["073375003032", "Gommersheim", null], - ["073375003035", "Großfischlingen", null], - ["073375003036", "Hainfeld", null], - ["073375003048", "Kleinfischlingen", null], - ["073375003066", "Rhodt unter Rietburg", null], - ["073375003069", "Roschbach", null], - ["073375003077", "Venningen", null], - ["073375003084", "Weyher in der Pfalz", null], - ["073375004038", "Herxheim bei Landau/ Pfalz", null], - ["073375004039", "Herxheimweyher", null], - ["073375004044", "Insheim", null], - ["073375004068", "Rohrbach", null], - ["073375005007", "Billigheim-Ingenheim", null], - ["073375005009", "Birkweiler", null], - ["073375005012", "Böchingen", null], - ["073375005022", "Eschbach", null], - ["073375005026", "Frankweiler", null], - ["073375005031", "Göcklingen", null], - ["073375005040", "Heuchelheim-Klingen", null], - ["073375005042", "Ilbesheim bei Landau in der Pfalz", null], - ["073375005043", "Impflingen", null], - ["073375005050", "Knöringen", null], - ["073375005051", "Leinsweiler", null], - ["073375005065", "Ranschbach", null], - ["073375005073", "Siebeldingen", null], - ["073375005082", "Walsheim", null], - ["073375006047", "Kirrweiler (Pfalz)", null], - ["073375006052", "Maikammer", null], - ["073375006070", "Sankt Martin", null], - ["073375007014", "Bornheim", null], - ["073375007023", "Essingen", null], - ["073375007041", "Hochstadt (Pfalz)", null], - ["073375007061", "Offenbach an der Queich", null], - ["073380004004", "Bobenheim-Roxheim", null], - ["073380005005", "Böhl-Iggelheim", null], - ["073380017017", "Limburgerhof", null], - ["073380019019", "Mutterstadt", null], - ["073380025025", "Schifferstadt, Stadt", null], - ["073385001006", "Dannstadt-Schauernheim", null], - ["073385001014", "Hochdorf-Assenheim", null], - ["073385001022", "Rödersheim-Gronau", null], - ["073385004003", "Birkenheide", null], - ["073385004008", "Fußgönheim", null], - ["073385004018", "Maxdorf", null], - ["073385006002", "Beindersheim", null], - ["073385006009", "Großniedesheim", null], - ["073385006012", "Heßheim", null], - ["073385006013", "Heuchelheim bei Frankenthal", null], - ["073385006015", "Kleinniedesheim", null], - ["073385006016", "Lambsheim", null], - ["073385007007", "Dudenhofen", null], - ["073385007010", "Hanhofen", null], - ["073385007011", "Harthausen", null], - ["073385007023", "Römerberg", null], - ["073385008001", "Altrip", null], - ["073385008020", "Neuhofen", null], - ["073385008021", "Otterstadt", null], - ["073385008026", "Waldsee", null], - ["073390005005", "Bingen am Rhein, Stadt", null], - ["073390009009", "Budenheim", null], - ["073390030030", "Ingelheim am Rhein, Stadt", null], - ["073395001003", "Bacharach, Stadt", null], - ["073395001007", "Breitscheid", null], - ["073395001036", "Manubach", null], - ["073395001038", "Münster-Sarmsheim", null], - ["073395001040", "Niederheimbach", null], - ["073395001044", "Oberdiebach", null], - ["073395001045", "Oberheimbach", null], - ["073395001058", "Trechtingshausen", null], - ["073395001062", "Waldalgesheim", null], - ["073395001063", "Weiler bei Bingen", null], - ["073395002006", "Bodenheim", null], - ["073395002020", "Gau-Bischofsheim", null], - ["073395002026", "Harxheim", null], - ["073395002034", "Lörzweiler", null], - ["073395002039", "Nackenheim", null], - ["073395003001", "Appenheim", null], - ["073395003008", "Bubenheim", null], - ["073395003016", "Engelstadt", null], - ["073395003019", "Gau-Algesheim, Stadt", null], - ["073395003041", "Nieder-Hilbersheim", null], - ["073395003046", "Ober-Hilbersheim", null], - ["073395003048", "Ockenheim", null], - ["073395003051", "Schwabenheim an der Selz", null], - ["073395006017", "Essenheim", null], - ["073395006031", "Jugenheim in Rheinhessen", null], - ["073395006032", "Klein-Winternheim", null], - ["073395006042", "Nieder-Olm, Stadt", null], - ["073395006047", "Ober-Olm", null], - ["073395006054", "Sörgenloch", null], - ["073395006057", "Stadecken-Elsheim", null], - ["073395006067", "Zornheim", null], - ["073395007010", "Dalheim", null], - ["073395007011", "Dexheim", null], - ["073395007012", "Dienheim", null], - ["073395007013", "Dolgesheim", null], - ["073395007015", "Eimsheim", null], - ["073395007018", "Friesenheim", null], - ["073395007024", "Guntersblum", null], - ["073395007025", "Hahnheim", null], - ["073395007028", "Hillesheim", null], - ["073395007033", "Köngernheim", null], - ["073395007035", "Ludwigshöhe", null], - ["073395007037", "Mommenheim", null], - ["073395007043", "Nierstein, Stadt", null], - ["073395007049", "Oppenheim, Stadt", null], - ["073395007053", "Selzen", null], - ["073395007059", "Uelversheim", null], - ["073395007060", "Undenheim", null], - ["073395007064", "Weinolsheim", null], - ["073395007066", "Wintersheim", null], - ["073395007201", "Dorn-Dürkheim", null], - ["073395008002", "Aspisheim", null], - ["073395008004", "Badenheim", null], - ["073395008021", "Gensingen", null], - ["073395008022", "Grolsheim", null], - ["073395008029", "Horrweiler", null], - ["073395008050", "Sankt Johann", null], - ["073395008056", "Sprendlingen", null], - ["073395008065", "Welgesheim", null], - ["073395008068", "Zotzenheim", null], - ["073395008202", "Wolfsheim", null], - ["073405001001", "Bobenthal", null], - ["073405001002", "Busenberg", null], - ["073405001004", "Dahn, Stadt", null], - ["073405001009", "Erfweiler", null], - ["073405001010", "Erlenbach bei Dahn", null], - ["073405001011", "Fischbach bei Dahn", null], - ["073405001021", "Hirschthal", null], - ["073405001029", "Ludwigswinkel", null], - ["073405001033", "Niederschlettenbach", null], - ["073405001034", "Nothweiler", null], - ["073405001039", "Rumbach", null], - ["073405001043", "Schindhard", null], - ["073405001045", "Schönau (Pfalz)", null], - ["073405001501", "Bruchweiler-Bärenbach", null], - ["073405001502", "Bundenthal", null], - ["073405002005", "Darstein", null], - ["073405002006", "Dimbach", null], - ["073405002014", "Hauenstein", null], - ["073405002020", "Hinterweidenthal", null], - ["073405002030", "Lug", null], - ["073405002047", "Schwanheim", null], - ["073405002049", "Spirkelbach", null], - ["073405002057", "Wilgartswiesen", null], - ["073405003008", "Eppenbrunn", null], - ["073405003019", "Hilst", null], - ["073405003026", "Kröppen", null], - ["073405003028", "Lemberg", null], - ["073405003036", "Obersimten", null], - ["073405003040", "Ruppertsweiler", null], - ["073405003048", "Schweix", null], - ["073405003052", "Trulben", null], - ["073405003053", "Vinningen", null], - ["073405003205", "Bottenbach", null], - ["073405004003", "Clausen", null], - ["073405004007", "Donsieders", null], - ["073405004027", "Leimen", null], - ["073405004031", "Merzalben", null], - ["073405004032", "Münchweiler an der Rodalb", null], - ["073405004038", "Rodalben, Stadt", null], - ["073405006012", "Geiselberg", null], - ["073405006015", "Heltersberg", null], - ["073405006016", "Hermersberg", null], - ["073405006022", "Höheinöd", null], - ["073405006025", "Horbach", null], - ["073405006044", "Schmalenberg", null], - ["073405006050", "Steinalben", null], - ["073405006054", "Waldfischbach-Burgalben", null], - ["073405008201", "Althornbach", null], - ["073405008202", "Battweiler", null], - ["073405008203", "Bechhofen", null], - ["073405008206", "Contwig", null], - ["073405008207", "Dellfeld", null], - ["073405008208", "Dietrichingen", null], - ["073405008209", "Großbundenbach", null], - ["073405008210", "Großsteinhausen", null], - ["073405008211", "Hornbach, Stadt", null], - ["073405008212", "Käshofen", null], - ["073405008213", "Kleinbundenbach", null], - ["073405008214", "Kleinsteinhausen", null], - ["073405008218", "Mauschbach", null], - ["073405008221", "Riedelberg", null], - ["073405008223", "Rosenkopf", null], - ["073405008226", "Walshausen", null], - ["073405008227", "Wiesbach", null], - ["073405009017", "Herschberg", null], - ["073405009018", "Hettenhausen", null], - ["073405009023", "Höheischweiler", null], - ["073405009024", "Höhfröschen", null], - ["073405009035", "Nünschweiler", null], - ["073405009037", "Petersberg", null], - ["073405009041", "Saalstadt", null], - ["073405009042", "Schauerberg", null], - ["073405009051", "Thaleischweiler-Fröschen", null], - ["073405009055", "Weselberg", null], - ["073405009204", "Biedershausen", null], - ["073405009215", "Knopp-Labach", null], - ["073405009216", "Krähenberg", null], - ["073405009217", "Maßweiler", null], - ["073405009219", "Obernheim-Kirchenarnbach", null], - ["073405009220", "Reifenberg", null], - ["073405009222", "Rieschweiler-Mühlbach", null], - ["073405009224", "Schmitshausen", null], - ["073405009225", "Wallhalben", null], - ["073405009228", "Winterbach (Pfalz)", null], - ["081110000000", "Stuttgart, Landeshauptstadt", null], - ["081150003003", "Böblingen, Stadt", null], - ["081150028028", "Leonberg, Stadt", null], - ["081150029029", "Magstadt", null], - ["081150041041", "Renningen, Stadt", null], - ["081150042042", "Rutesheim, Stadt", null], - ["081150044044", "Schönaich", null], - ["081150045045", "Sindelfingen, Stadt", null], - ["081150050050", "Weil der Stadt, Stadt", null], - ["081150051051", "Weil im Schönbuch", null], - ["081150052052", "Weissach", null], - ["081155001001", "Aidlingen", null], - ["081155001054", "Grafenau", null], - ["081155002013", "Ehningen", null], - ["081155002015", "Gärtringen", null], - ["081155003010", "Deckenpfronn", null], - ["081155003021", "Herrenberg, Stadt", null], - ["081155003037", "Nufringen", null], - ["081155004002", "Altdorf", null], - ["081155004022", "Hildrizhausen", null], - ["081155004024", "Holzgerlingen, Stadt", null], - ["081155005004", "Bondorf", null], - ["081155005016", "Gäufelden", null], - ["081155005034", "Mötzingen", null], - ["081155005053", "Jettingen", null], - ["081155006046", "Steinenbronn", null], - ["081155006048", "Waldenbuch, Stadt", null], - ["081160015015", "Denkendorf", null], - ["081160019019", "Esslingen am Neckar, Stadt", null], - ["081160047047", "Neuhausen auf den Fildern", null], - ["081160072072", "Wernau (Neckar), Stadt", null], - ["081160076076", "Aichwald", null], - ["081160077077", "Filderstadt, Stadt", null], - ["081160078078", "Leinfelden-Echterdingen, Stadt", null], - ["081160080080", "Ostfildern, Stadt", null], - ["081160081081", "Aichtal, Stadt", null], - ["081165001016", "Dettingen unter Teck", null], - ["081165001033", "Kirchheim unter Teck, Stadt", null], - ["081165001048", "Notzingen", null], - ["081165002018", "Erkenbrechtsweiler", null], - ["081165002054", "Owen, Stadt", null], - ["081165002079", "Lenningen", null], - ["081165003005", "Altdorf", null], - ["081165003006", "Altenriet", null], - ["081165003008", "Bempflingen", null], - ["081165003041", "Neckartailfingen", null], - ["081165003042", "Neckartenzlingen", null], - ["081165003063", "Schlaitdorf", null], - ["081165004011", "Beuren", null], - ["081165004036", "Kohlberg", null], - ["081165004046", "Neuffen, Stadt", null], - ["081165005020", "Frickenhausen", null], - ["081165005022", "Großbettlingen", null], - ["081165005049", "Nürtingen, Stadt", null], - ["081165005050", "Oberboihingen", null], - ["081165005068", "Unterensingen", null], - ["081165005073", "Wolfschlugen", null], - ["081165006004", "Altbach", null], - ["081165006014", "Deizisau", null], - ["081165006056", "Plochingen, Stadt", null], - ["081165007007", "Baltmannsweiler", null], - ["081165007027", "Hochdorf", null], - ["081165007037", "Lichtenwald", null], - ["081165007058", "Reichenbach an der Fils", null], - ["081165008012", "Bissingen an der Teck", null], - ["081165008029", "Holzmaden", null], - ["081165008043", "Neidlingen", null], - ["081165008053", "Ohmden", null], - ["081165008070", "Weilheim an der Teck, Stadt", null], - ["081165009035", "Köngen", null], - ["081165009071", "Wendlingen am Neckar, Stadt", null], - ["081170010010", "Böhmenkirch", null], - ["081175001006", "Bad Ditzenbach", null], - ["081175001014", "Deggingen", null], - ["081175002018", "Ebersbach an der Fils, Stadt", null], - ["081175002044", "Schlierbach", null], - ["081175003019", "Eislingen/Fils, Stadt", null], - ["081175003037", "Ottenbach", null], - ["081175003042", "Salach", null], - ["081175004007", "Bad Überkingen", null], - ["081175004024", "Geislingen an der Steige, Stadt", null], - ["081175004033", "Kuchen", null], - ["081175005026", "Göppingen, Stadt", null], - ["081175005043", "Schlat", null], - ["081175005053", "Wäschenbeuren", null], - ["081175005055", "Wangen", null], - ["081175006015", "Donzdorf, Stadt", null], - ["081175006025", "Gingen an der Fils", null], - ["081175006049", "Süßen, Stadt", null], - ["081175006061", "Lauterstein, Stadt", null], - ["081175007016", "Drackenstein", null], - ["081175007028", "Gruibingen", null], - ["081175007031", "Hohenstadt", null], - ["081175007035", "Mühlhausen im Täle", null], - ["081175007058", "Wiesensteig, Stadt", null], - ["081175008001", "Adelberg", null], - ["081175008009", "Birenbach", null], - ["081175008011", "Börtlingen", null], - ["081175008038", "Rechberghausen", null], - ["081175009002", "Aichelberg", null], - ["081175009012", "Bad Boll", null], - ["081175009017", "Dürnau", null], - ["081175009023", "Gammelshausen", null], - ["081175009029", "Hattenhofen", null], - ["081175009060", "Zell unter Aichelberg", null], - ["081175010003", "Albershausen", null], - ["081175010051", "Uhingen, Stadt", null], - ["081175011020", "Eschenbach", null], - ["081175011030", "Heiningen", null], - ["081180003003", "Asperg, Stadt", null], - ["081180011011", "Ditzingen, Stadt", null], - ["081180019019", "Gerlingen, Stadt", null], - ["081180021021", "Großbottwar, Stadt", null], - ["081180046046", "Kornwestheim, Stadt", null], - ["081180048048", "Ludwigsburg, Stadt", null], - ["081180050050", "Markgröningen, Stadt", null], - ["081180051051", "Möglingen", null], - ["081180060060", "Oberstenfeld", null], - ["081180076076", "Sachsenheim, Stadt", null], - ["081180080080", "Korntal-Münchingen, Stadt", null], - ["081180081081", "Remseck am Neckar, Stadt", null], - ["081185001007", "Besigheim, Stadt", null], - ["081185001016", "Freudental", null], - ["081185001018", "Gemmrigheim", null], - ["081185001028", "Hessigheim", null], - ["081185001047", "Löchgau", null], - ["081185001053", "Mundelsheim", null], - ["081185001074", "Walheim", null], - ["081185002071", "Tamm", null], - ["081185002077", "Ingersheim", null], - ["081185002079", "Bietigheim-Bissingen, Stadt", null], - ["081185003010", "Bönnigheim, Stadt", null], - ["081185003015", "Erligheim", null], - ["081185003040", "Kirchheim am Neckar", null], - ["081185004063", "Pleidelsheim", null], - ["081185004078", "Freiberg am Neckar, Stadt", null], - ["081185005001", "Affalterbach", null], - ["081185005006", "Benningen am Neckar", null], - ["081185005014", "Erdmannhausen", null], - ["081185005049", "Marbach am Neckar, Stadt", null], - ["081185006027", "Hemmingen", null], - ["081185006067", "Schwieberdingen", null], - ["081185007054", "Murr", null], - ["081185007070", "Steinheim an der Murr, Stadt", null], - ["081185008012", "Eberdingen", null], - ["081185008059", "Oberriexingen, Stadt", null], - ["081185008068", "Sersheim", null], - ["081185008073", "Vaihingen an der Enz, Stadt", null], - ["081190001001", "Alfdorf", null], - ["081190020020", "Fellbach, Stadt", null], - ["081190041041", "Korb", null], - ["081190044044", "Murrhardt, Stadt", null], - ["081190061061", "Rudersberg", null], - ["081190079079", "Waiblingen, Stadt", null], - ["081190089089", "Berglen", null], - ["081190090090", "Remshalden", null], - ["081190091091", "Weinstadt, Stadt", null], - ["081190093093", "Kernen im Remstal", null], - ["081195001003", "Allmersbach im Tal", null], - ["081195001004", "Althütte", null], - ["081195001006", "Auenwald", null], - ["081195001008", "Backnang, Stadt", null], - ["081195001018", "Burgstetten", null], - ["081195001038", "Kirchberg an der Murr", null], - ["081195001053", "Oppenweiler", null], - ["081195001083", "Weissach im Tal", null], - ["081195001087", "Aspach", null], - ["081195002055", "Plüderhausen", null], - ["081195002076", "Urbach", null], - ["081195003067", "Schorndorf, Stadt", null], - ["081195003086", "Winterbach", null], - ["081195004024", "Großerlach", null], - ["081195004069", "Spiegelberg", null], - ["081195004075", "Sulzbach an der Murr", null], - ["081195005037", "Kaisersbach", null], - ["081195005084", "Welzheim, Stadt", null], - ["081195006042", "Leutenbach", null], - ["081195006068", "Schwaikheim", null], - ["081195006085", "Winnenden, Stadt", null], - ["081210000000", "Heilbronn, Universitätsstadt", null], - ["081250007007", "Bad Wimpfen, Stadt", null], - ["081250039039", "Gundelsheim, Stadt", null], - ["081250058058", "Leingarten, Stadt", null], - ["081250068068", "Neudenau, Stadt", null], - ["081250107107", "Wüstenrot", null], - ["081255001005", "Bad Friedrichshall, Stadt", null], - ["081255001078", "Oedheim", null], - ["081255001079", "Offenau", null], - ["081255002006", "Bad Rappenau, Stadt", null], - ["081255002049", "Kirchardt", null], - ["081255002087", "Siegelsbach", null], - ["081255003013", "Brackenheim, Stadt", null], - ["081255003017", "Cleebronn", null], - ["081255004026", "Eppingen, Stadt", null], - ["081255004034", "Gemmingen", null], - ["081255004047", "Ittlingen", null], - ["081255005030", "Flein", null], - ["081255005094", "Talheim", null], - ["081255006056", "Lauffen am Neckar, Stadt", null], - ["081255006066", "Neckarwestheim", null], - ["081255006074", "Nordheim", null], - ["081255007048", "Jagsthausen", null], - ["081255007063", "Möckmühl, Stadt", null], - ["081255007084", "Roigheim", null], - ["081255007103", "Widdern, Stadt", null], - ["081255008027", "Erlenbach", null], - ["081255008065", "Neckarsulm, Stadt", null], - ["081255008096", "Untereisesheim", null], - ["081255009069", "Neuenstadt am Kocher, Stadt", null], - ["081255009111", "Hardthausen am Kocher", null], - ["081255009113", "Langenbrettach", null], - ["081255010038", "Güglingen, Stadt", null], - ["081255010081", "Pfaffenhofen", null], - ["081255010108", "Zaberfeld", null], - ["081255011059", "Löwenstein, Stadt", null], - ["081255011110", "Obersulm", null], - ["081255012001", "Abstatt", null], - ["081255012008", "Beilstein, Stadt", null], - ["081255012046", "Ilsfeld", null], - ["081255012098", "Untergruppenbach", null], - ["081255013061", "Massenbachhausen", null], - ["081255013086", "Schwaigern, Stadt", null], - ["081255014021", "Eberstadt", null], - ["081255014024", "Ellhofen", null], - ["081255014057", "Lehrensteinsfeld", null], - ["081255014102", "Weinsberg, Stadt", null], - ["081260011011", "Bretzfeld", null], - ["081260072072", "Schöntal", null], - ["081265001047", "Kupferzell", null], - ["081265001058", "Neuenstein, Stadt", null], - ["081265001085", "Waldenburg, Stadt", null], - ["081265002020", "Dörzbach", null], - ["081265002045", "Krautheim, Stadt", null], - ["081265002056", "Mulfingen", null], - ["081265003039", "Ingelfingen, Stadt", null], - ["081265003046", "Künzelsau, Stadt", null], - ["081265004028", "Forchtenberg, Stadt", null], - ["081265004060", "Niedernhall, Stadt", null], - ["081265004086", "Weißbach", null], - ["081265005066", "Öhringen, Stadt", null], - ["081265005069", "Pfedelbach", null], - ["081265005094", "Zweiflingen", null], - ["081270008008", "Blaufelden", null], - ["081270052052", "Mainhardt", null], - ["081270075075", "Schrozberg, Stadt", null], - ["081275001009", "Braunsbach", null], - ["081275001086", "Untermünkheim", null], - ["081275002014", "Crailsheim, Stadt", null], - ["081275002073", "Satteldorf", null], - ["081275002103", "Frankenhardt", null], - ["081275002104", "Stimpfach", null], - ["081275003101", "Kreßberg", null], - ["081275003102", "Fichtenau", null], - ["081275004032", "Gerabronn, Stadt", null], - ["081275004047", "Langenburg, Stadt", null], - ["081275005043", "Ilshofen, Stadt", null], - ["081275005089", "Vellberg, Stadt", null], - ["081275005099", "Wolpertshausen", null], - ["081275006023", "Fichtenberg", null], - ["081275006025", "Gaildorf, Stadt", null], - ["081275006062", "Oberrot", null], - ["081275006079", "Sulzbach-Laufen", null], - ["081275007012", "Bühlertann", null], - ["081275007013", "Bühlerzell", null], - ["081275007063", "Obersontheim", null], - ["081275008046", "Kirchberg an der Jagst, Stadt", null], - ["081275008071", "Rot am See", null], - ["081275008091", "Wallhausen", null], - ["081275009056", "Michelbach an der Bilz", null], - ["081275009059", "Michelfeld", null], - ["081275009076", "Schwäbisch Hall, Stadt", null], - ["081275009100", "Rosengarten", null], - ["081280020020", "Creglingen, Stadt", null], - ["081280039039", "Freudenberg, Stadt", null], - ["081280064064", "Külsheim, Stadt", null], - ["081280082082", "Niederstetten, Stadt", null], - ["081280126126", "Weikersheim, Stadt", null], - ["081280131131", "Wertheim, Stadt", null], - ["081280139139", "Lauda-Königshofen, Stadt", null], - ["081285001006", "Assamstadt", null], - ["081285001007", "Bad Mergentheim, Stadt", null], - ["081285001058", "Igersheim", null], - ["081285002014", "Boxberg, Stadt", null], - ["081285002138", "Ahorn", null], - ["081285003047", "Grünsfeld, Stadt", null], - ["081285003137", "Wittighausen", null], - ["081285004045", "Großrinderfeld", null], - ["081285004061", "Königheim", null], - ["081285004115", "Tauberbischofsheim, Stadt", null], - ["081285004128", "Werbach", null], - ["081350010010", "Dischingen", null], - ["081350015015", "Gerstetten", null], - ["081350020020", "Herbrechtingen, Stadt", null], - ["081350025025", "Königsbronn", null], - ["081350032032", "Steinheim am Albuch", null], - ["081355001016", "Giengen an der Brenz, Stadt", null], - ["081355001021", "Hermaringen", null], - ["081355002019", "Heidenheim an der Brenz, Stadt", null], - ["081355002026", "Nattheim", null], - ["081355003027", "Niederstotzingen, Stadt", null], - ["081355003031", "Sontheim an der Brenz", null], - ["081360002002", "Abtsgmünd", null], - ["081360027027", "Gschwend", null], - ["081360042042", "Lorch, Stadt", null], - ["081360045045", "Neresheim, Stadt", null], - ["081360050050", "Oberkochen, Stadt", null], - ["081365001021", "Essingen", null], - ["081365001033", "Hüttlingen", null], - ["081365001088", "Aalen, Stadt", null], - ["081365002010", "Bopfingen, Stadt", null], - ["081365002037", "Kirchheim am Ries", null], - ["081365002087", "Riesbürg", null], - ["081365003003", "Adelmannsfelden", null], - ["081365003018", "Ellenberg", null], - ["081365003019", "Ellwangen (Jagst), Stadt", null], - ["081365003035", "Jagstzell", null], - ["081365003046", "Neuler", null], - ["081365003060", "Rosenberg", null], - ["081365003084", "Wört", null], - ["081365003089", "Rainau", null], - ["081365004038", "Lauchheim, Stadt", null], - ["081365004082", "Westhausen", null], - ["081365005020", "Eschach", null], - ["081365005024", "Göggingen", null], - ["081365005034", "Iggingen", null], - ["081365005040", "Leinzell", null], - ["081365005049", "Obergröningen", null], - ["081365005062", "Schechingen", null], - ["081365006007", "Bartholomä", null], - ["081365006009", "Böbingen an der Rems", null], - ["081365006028", "Heubach, Stadt", null], - ["081365006029", "Heuchlingen", null], - ["081365006043", "Mögglingen", null], - ["081365007065", "Schwäbisch Gmünd, Stadt", null], - ["081365007079", "Waldstetten", null], - ["081365008015", "Durlangen", null], - ["081365008044", "Mutlangen", null], - ["081365008061", "Ruppertshofen", null], - ["081365008066", "Spraitbach", null], - ["081365008070", "Täferrot", null], - ["081365009068", "Stödtlen", null], - ["081365009071", "Tannhausen", null], - ["081365009075", "Unterschneidheim", null], - ["082110000000", "Baden-Baden, Stadt", null], - ["082120000000", "Karlsruhe, Stadt", null], - ["082150017017", "Ettlingen, Stadt", null], - ["082150046046", "Malsch", null], - ["082150047047", "Marxzell", null], - ["082150064064", "Östringen, Stadt", null], - ["082150084084", "Ubstadt-Weiher", null], - ["082150089089", "Walzbachtal", null], - ["082150090090", "Weingarten (Baden)", null], - ["082150096096", "Karlsbad", null], - ["082150097097", "Kraichtal, Stadt", null], - ["082150101101", "Pfinztal", null], - ["082150102102", "Eggenstein-Leopoldshafen", null], - ["082150105105", "Linkenheim-Hochstetten", null], - ["082150106106", "Waghäusel, Stadt", null], - ["082150108108", "Rheinstetten, Stadt", null], - ["082150109109", "Stutensee, Stadt", null], - ["082150110110", "Waldbronn", null], - ["082155001039", "Kronau", null], - ["082155001100", "Bad Schönborn", null], - ["082155002007", "Bretten, Stadt", null], - ["082155002025", "Gondelsheim", null], - ["082155003009", "Bruchsal, Stadt", null], - ["082155003021", "Forst", null], - ["082155003029", "Hambrücken", null], - ["082155003103", "Karlsdorf-Neuthard", null], - ["082155004099", "Graben-Neudorf", null], - ["082155004111", "Dettenheim", null], - ["082155005040", "Kürnbach", null], - ["082155005059", "Oberderdingen", null], - ["082155006066", "Philippsburg, Stadt", null], - ["082155006107", "Oberhausen-Rheinhausen", null], - ["082155007082", "Sulzfeld", null], - ["082155007094", "Zaisenhausen", null], - ["082160008008", "Bühlertal", null], - ["082160013013", "Forbach", null], - ["082160015015", "Gaggenau, Stadt", null], - ["082165001006", "Bischweier", null], - ["082165001024", "Kuppenheim, Stadt", null], - ["082165002007", "Bühl, Stadt", null], - ["082165002041", "Ottersweier", null], - ["082165003002", "Au am Rhein", null], - ["082165003005", "Bietigheim", null], - ["082165003009", "Durmersheim", null], - ["082165003012", "Elchesheim-Illingen", null], - ["082165004017", "Gernsbach, Stadt", null], - ["082165004029", "Loffenau", null], - ["082165004059", "Weisenbach", null], - ["082165005023", "Iffezheim", null], - ["082165005033", "Muggensturm", null], - ["082165005039", "Ötigheim", null], - ["082165005043", "Rastatt, Stadt", null], - ["082165005052", "Steinmauern", null], - ["082165006028", "Lichtenau, Stadt", null], - ["082165006063", "Rheinmünster", null], - ["082165007022", "Hügelsheim", null], - ["082165007049", "Sinzheim", null], - ["082210000000", "Heidelberg, Stadt", null], - ["082220000000", "Mannheim, Universitätsstadt", null], - ["082250014014", "Buchen (Odenwald), Stadt", null], - ["082250060060", "Mudau", null], - ["082255001032", "Hardheim", null], - ["082255001039", "Höpfingen", null], - ["082255001109", "Walldürn, Stadt", null], - ["082255002033", "Haßmersheim", null], - ["082255002042", "Hüffenhardt", null], - ["082255003002", "Aglasterhausen", null], - ["082255003068", "Neunkirchen", null], - ["082255003116", "Schwarzach", null], - ["082255004024", "Fahrenbach", null], - ["082255004052", "Limbach", null], - ["082255005058", "Mosbach, Stadt", null], - ["082255005067", "Neckarzimmern", null], - ["082255005074", "Obrigheim", null], - ["082255005117", "Elztal", null], - ["082255006010", "Binau", null], - ["082255006064", "Neckargerach", null], - ["082255006113", "Zwingenberg", null], - ["082255006118", "Waldbrunn", null], - ["082255007075", "Osterburken, Stadt", null], - ["082255007082", "Rosenberg", null], - ["082255007114", "Ravenstein, Stadt", null], - ["082255008009", "Billigheim", null], - ["082255008115", "Schefflenz", null], - ["082255009001", "Adelsheim, Stadt", null], - ["082255009091", "Seckach", null], - ["082260009009", "Brühl", null], - ["082260012012", "Dossenheim", null], - ["082260018018", "Eppelheim, Stadt", null], - ["082260028028", "Heddesheim", null], - ["082260036036", "Ilvesheim", null], - ["082260037037", "Ketsch", null], - ["082260038038", "Ladenburg, Stadt", null], - ["082260041041", "Leimen, Stadt", null], - ["082260060060", "Nußloch", null], - ["082260062062", "Oftersheim", null], - ["082260063063", "Plankstadt", null], - ["082260076076", "Sandhausen", null], - ["082260082082", "Schriesheim, Stadt", null], - ["082260084084", "Schwetzingen, Stadt", null], - ["082260095095", "Walldorf, Stadt", null], - ["082260096096", "Weinheim, Stadt", null], - ["082260103103", "St. Leon-Rot", null], - ["082260105105", "Edingen-Neckarhausen", null], - ["082260107107", "Hirschberg an der Bergstraße", null], - ["082265001013", "Eberbach, Stadt", null], - ["082265001081", "Schönbrunn", null], - ["082265002020", "Eschelbronn", null], - ["082265002048", "Mauer", null], - ["082265002049", "Meckesheim", null], - ["082265002086", "Spechbach", null], - ["082265002104", "Lobbach", null], - ["082265003031", "Hemsbach, Stadt", null], - ["082265003040", "Laudenbach", null], - ["082265004003", "Altlußheim", null], - ["082265004032", "Hockenheim, Stadt", null], - ["082265004059", "Neulußheim", null], - ["082265004068", "Reilingen", null], - ["082265005006", "Bammental", null], - ["082265005022", "Gaiberg", null], - ["082265005056", "Neckargemünd, Stadt", null], - ["082265005097", "Wiesenbach", null], - ["082265006046", "Malsch", null], - ["082265006054", "Mühlhausen", null], - ["082265006065", "Rauenberg, Stadt", null], - ["082265007027", "Heddesbach", null], - ["082265007029", "Heiligkreuzsteinach", null], - ["082265007080", "Schönau, Stadt", null], - ["082265007099", "Wilhelmsfeld", null], - ["082265008085", "Sinsheim, Stadt", null], - ["082265008101", "Zuzenhausen", null], - ["082265008102", "Angelbachtal", null], - ["082265009017", "Epfenbach", null], - ["082265009055", "Neckarbischofsheim, Stadt", null], - ["082265009058", "Neidenstein", null], - ["082265009066", "Reichartshausen", null], - ["082265009091", "Waibstadt, Stadt", null], - ["082265009106", "Helmstadt-Bargen", null], - ["082265010010", "Dielheim", null], - ["082265010098", "Wiesloch, Stadt", null], - ["082310000000", "Pforzheim, Stadt", null], - ["082350065065", "Schömberg", null], - ["082350080080", "Wildberg, Stadt", null], - ["082355001006", "Altensteig, Stadt", null], - ["082355001022", "Egenhausen", null], - ["082355001066", "Simmersfeld", null], - ["082355002007", "Althengstett", null], - ["082355002029", "Gechingen", null], - ["082355002057", "Ostelsheim", null], - ["082355002067", "Simmozheim", null], - ["082355003018", "Dobel", null], - ["082355003033", "Bad Herrenalb, Stadt", null], - ["082355004008", "Bad Liebenzell, Stadt", null], - ["082355004073", "Unterreichenbach", null], - ["082355005047", "Neubulach, Stadt", null], - ["082355005050", "Neuweiler", null], - ["082355005084", "Bad Teinach-Zavelstein, Stadt", null], - ["082355006055", "Oberreichenbach", null], - ["082355006085", "Calw, Stadt", null], - ["082355007020", "Ebhausen", null], - ["082355007032", "Haiterbach, Stadt", null], - ["082355007046", "Nagold, Stadt", null], - ["082355007060", "Rohrdorf", null], - ["082355008025", "Enzklösterle", null], - ["082355008035", "Höfen an der Enz", null], - ["082355008079", "Bad Wildbad, Stadt", null], - ["082360004004", "Birkenfeld", null], - ["082360028028", "Illingen", null], - ["082360030030", "Ispringen", null], - ["082360033033", "Knittlingen, Stadt", null], - ["082360046046", "Niefern-Öschelbronn", null], - ["082360070070", "Keltern", null], - ["082360071071", "Remchingen", null], - ["082360072072", "Straubenhardt", null], - ["082365001019", "Friolzheim", null], - ["082365001025", "Heimsheim, Stadt", null], - ["082365001039", "Mönsheim", null], - ["082365001065", "Wiernsheim", null], - ["082365001067", "Wimsheim", null], - ["082365001068", "Wurmberg", null], - ["082365002011", "Eisingen", null], - ["082365002074", "Kämpfelbach", null], - ["082365002076", "Königsbach-Stein", null], - ["082365003038", "Maulbronn, Stadt", null], - ["082365003061", "Sternenfels", null], - ["082365004040", "Mühlacker, Stadt", null], - ["082365004050", "Ötisheim", null], - ["082365005013", "Engelsbrand", null], - ["082365005043", "Neuenbürg, Stadt", null], - ["082365006031", "Kieselbronn", null], - ["082365006073", "Neulingen", null], - ["082365006075", "Ölbronn-Dürrn", null], - ["082365007044", "Neuhausen", null], - ["082365007062", "Tiefenbronn", null], - ["082370002002", "Alpirsbach, Stadt", null], - ["082370004004", "Baiersbronn", null], - ["082370045045", "Loßburg", null], - ["082375001019", "Dornstetten, Stadt", null], - ["082375001030", "Glatten", null], - ["082375001061", "Schopfloch", null], - ["082375001074", "Waldachtal", null], - ["082375002028", "Freudenstadt, Stadt", null], - ["082375002073", "Seewald", null], - ["082375002075", "Bad Rippoldsau-Schapbach", null], - ["082375003024", "Empfingen", null], - ["082375003027", "Eutingen im Gäu", null], - ["082375003040", "Horb am Neckar, Stadt", null], - ["082375005032", "Grömbach", null], - ["082375005054", "Pfalzgrafenweiler", null], - ["082375005072", "Wörnersberg", null], - ["083110000000", "Freiburg im Breisgau, Stadt", null], - ["083150068068", "Lenzkirch", null], - ["083150076076", "Neuenburg am Rhein, Stadt", null], - ["083150133133", "Vogtsburg im Kaiserstuhl, Stadt", null], - ["083155001006", "Bad Krozingen, Stadt", null], - ["083155001048", "Hartheim am Rhein", null], - ["083155002015", "Breisach am Rhein, Stadt", null], - ["083155002059", "Ihringen", null], - ["083155002072", "Merdingen", null], - ["083155003020", "Buchenbach", null], - ["083155003064", "Kirchzarten", null], - ["083155003084", "Oberried", null], - ["083155003109", "Stegen", null], - ["083155004014", "Bollschweil", null], - ["083155004131", "Ehrenkirchen", null], - ["083155005047", "Gundelfingen", null], - ["083155005051", "Heuweiler", null], - ["083155006008", "Ballrechten-Dottingen", null], - ["083155006033", "Eschbach", null], - ["083155006050", "Heitersheim, Stadt", null], - ["083155007003", "Au", null], - ["083155007056", "Horben", null], - ["083155007073", "Merzhausen", null], - ["083155007107", "Sölden", null], - ["083155007125", "Wittnau", null], - ["083155008016", "Breitnau", null], - ["083155008052", "Hinterzarten", null], - ["083155009013", "Bötzingen", null], - ["083155009030", "Eichstetten am Kaiserstuhl", null], - ["083155009043", "Gottenheim", null], - ["083155010039", "Friedenweiler", null], - ["083155010070", "Löffingen, Stadt", null], - ["083155011115", "Umkirch", null], - ["083155011132", "March", null], - ["083155012004", "Auggen", null], - ["083155012007", "Badenweiler", null], - ["083155012022", "Buggingen", null], - ["083155012074", "Müllheim, Stadt", null], - ["083155012111", "Sulzburg, Stadt", null], - ["083155013041", "Glottertal", null], - ["083155013094", "St. Märgen", null], - ["083155013095", "St. Peter", null], - ["083155014028", "Ebringen", null], - ["083155014089", "Pfaffenweiler", null], - ["083155014098", "Schallstadt", null], - ["083155015037", "Feldberg (Schwarzwald)", null], - ["083155015102", "Schluchsee", null], - ["083155016108", "Staufen im Breisgau, Stadt", null], - ["083155016130", "Münstertal/Schwarzwald", null], - ["083155017031", "Eisenbach (Hochschwarzwald)", null], - ["083155017113", "Titisee-Neustadt, Stadt", null], - ["083165001009", "Denzlingen", null], - ["083165001036", "Reute", null], - ["083165001045", "Vörstetten", null], - ["083165002003", "Biederbach", null], - ["083165002010", "Elzach, Stadt", null], - ["083165002055", "Winden im Elztal", null], - ["083165003011", "Emmendingen, Stadt", null], - ["083165003024", "Malterdingen", null], - ["083165003039", "Sexau", null], - ["083165003043", "Teningen", null], - ["083165003054", "Freiamt", null], - ["083165004017", "Herbolzheim, Stadt", null], - ["083165004020", "Kenzingen, Stadt", null], - ["083165004049", "Weisweil", null], - ["083165004053", "Rheinhausen", null], - ["083165005002", "Bahlingen am Kaiserstuhl", null], - ["083165005012", "Endingen am Kaiserstuhl, Stadt", null], - ["083165005013", "Forchheim", null], - ["083165005037", "Riegel am Kaiserstuhl", null], - ["083165005038", "Sasbach am Kaiserstuhl", null], - ["083165005051", "Wyhl am Kaiserstuhl", null], - ["083165006014", "Gutach im Breisgau", null], - ["083165006042", "Simonswald", null], - ["083165006056", "Waldkirch, Stadt", null], - ["083170005005", "Appenweier", null], - ["083170031031", "Friesenheim", null], - ["083170051051", "Hornberg, Stadt", null], - ["083170057057", "Kehl, Stadt", null], - ["083170141141", "Willstätt", null], - ["083170151151", "Neuried", null], - ["083170153153", "Rheinau, Stadt", null], - ["083175001001", "Achern, Stadt", null], - ["083175001068", "Lauf", null], - ["083175001116", "Sasbach", null], - ["083175001118", "Sasbachwalden", null], - ["083175002026", "Ettenheim, Stadt", null], - ["083175002073", "Mahlberg, Stadt", null], - ["083175002113", "Ringsheim", null], - ["083175002114", "Rust", null], - ["083175002152", "Kappel-Grafenhausen", null], - ["083175003009", "Berghaupten", null], - ["083175003034", "Gengenbach, Stadt", null], - ["083175003097", "Ohlsbach", null], - ["083175004029", "Fischerbach", null], - ["083175004040", "Haslach im Kinzigtal, Stadt", null], - ["083175004046", "Hofstetten", null], - ["083175004078", "Mühlenbach", null], - ["083175004129", "Steinach", null], - ["083175005039", "Gutach (Schwarzwaldbahn)", null], - ["083175005041", "Hausach, Stadt", null], - ["083175006056", "Kappelrodeck", null], - ["083175006102", "Ottenhöfen im Schwarzwald", null], - ["083175006126", "Seebach", null], - ["083175007059", "Kippenheim", null], - ["083175007065", "Lahr/Schwarzwald, Stadt", null], - ["083175008008", "Bad Peterstal-Griesbach", null], - ["083175008098", "Oppenau, Stadt", null], - ["083175009067", "Lautenbach", null], - ["083175009089", "Oberkirch, Stadt", null], - ["083175009110", "Renchen, Stadt", null], - ["083175010021", "Durbach", null], - ["083175010047", "Hohberg", null], - ["083175010096", "Offenburg, Stadt", null], - ["083175010100", "Ortenberg", null], - ["083175010122", "Schutterwald", null], - ["083175011121", "Schuttertal", null], - ["083175011127", "Seelbach", null], - ["083175012075", "Meißenheim", null], - ["083175012150", "Schwanau", null], - ["083175013093", "Oberwolfach", null], - ["083175013145", "Wolfach, Stadt", null], - ["083175014011", "Biberach", null], - ["083175014085", "Nordrach", null], - ["083175014088", "Oberharmersbach", null], - ["083175014146", "Zell am Harmersbach, Stadt", null], - ["083179971971", "Rheinau, gemeindefreies Gebiet", null], - ["083250012012", "Dornhan, Stadt", null], - ["083255001014", "Dunningen", null], - ["083255001071", "Eschbronn", null], - ["083255002015", "Epfendorf", null], - ["083255002045", "Oberndorf am Neckar, Stadt", null], - ["083255002070", "Fluorn-Winzeln", null], - ["083255003011", "Dietingen", null], - ["083255003049", "Rottweil, Stadt", null], - ["083255003064", "Wellendingen", null], - ["083255003069", "Zimmern ob Rottweil", null], - ["083255003072", "Deißlingen", null], - ["083255004050", "Schenkenzell", null], - ["083255004051", "Schiltach, Stadt", null], - ["083255005001", "Aichhalden", null], - ["083255005024", "Hardt", null], - ["083255005036", "Lauterbach", null], - ["083255005053", "Schramberg, Stadt", null], - ["083255006057", "Sulz am Neckar, Stadt", null], - ["083255006061", "Vöhringen", null], - ["083255007009", "Bösingen", null], - ["083255007060", "Villingendorf", null], - ["083260003003", "Bad Dürrheim, Stadt", null], - ["083260005005", "Blumberg, Stadt", null], - ["083260031031", "Königsfeld im Schwarzwald", null], - ["083260052052", "St. Georgen im Schwarzwald, Stadt", null], - ["083260068068", "Vöhrenbach, Stadt", null], - ["083265001006", "Bräunlingen, Stadt", null], - ["083265001012", "Donaueschingen, Stadt", null], - ["083265001027", "Hüfingen, Stadt", null], - ["083265002017", "Furtwangen im Schwarzwald, Stadt", null], - ["083265002020", "Gütenbach", null], - ["083265003054", "Schönwald im Schwarzwald", null], - ["083265003055", "Schonach im Schwarzwald", null], - ["083265003060", "Triberg im Schwarzwald, Stadt", null], - ["083265004010", "Dauchingen", null], - ["083265004037", "Mönchweiler", null], - ["083265004041", "Niedereschach", null], - ["083265004061", "Tuningen", null], - ["083265004065", "Unterkirnach", null], - ["083265004074", "Villingen-Schwenningen, Stadt", null], - ["083265004075", "Brigachtal", null], - ["083275001004", "Bärenthal", null], - ["083275001008", "Buchheim", null], - ["083275001016", "Fridingen an der Donau, Stadt", null], - ["083275001027", "Irndorf", null], - ["083275001030", "Kolbingen", null], - ["083275001036", "Mühlheim an der Donau, Stadt", null], - ["083275001041", "Renquishausen", null], - ["083275002007", "Bubsheim", null], - ["083275002009", "Deilingen", null], - ["083275002013", "Egesheim", null], - ["083275002019", "Gosheim", null], - ["083275002029", "Königsheim", null], - ["083275002040", "Reichenbach am Heuberg", null], - ["083275002051", "Wehingen", null], - ["083275003018", "Geisingen, Stadt", null], - ["083275003025", "Immendingen", null], - ["083275004002", "Aldingen", null], - ["083275004005", "Balgheim", null], - ["083275004006", "Böttingen", null], - ["083275004010", "Denkingen", null], - ["083275004011", "Dürbheim", null], - ["083275004017", "Frittlingen", null], - ["083275004023", "Hausen ob Verena", null], - ["083275004033", "Mahlstetten", null], - ["083275004046", "Spaichingen, Stadt", null], - ["083275005012", "Durchhausen", null], - ["083275005020", "Gunningen", null], - ["083275005048", "Talheim", null], - ["083275005049", "Trossingen, Stadt", null], - ["083275006038", "Neuhausen ob Eck", null], - ["083275006050", "Tuttlingen, Stadt", null], - ["083275006054", "Wurmlingen", null], - ["083275006055", "Seitingen-Oberflacht", null], - ["083275006056", "Rietheim-Weilheim", null], - ["083275006057", "Emmingen-Liptingen", null], - ["083350035035", "Hilzingen", null], - ["083350063063", "Radolfzell am Bodensee, Stadt", null], - ["083350080080", "Tengen, Stadt", null], - ["083355001001", "Aach, Stadt", null], - ["083355001022", "Engen, Stadt", null], - ["083355001097", "Mühlhausen-Ehingen", null], - ["083355002015", "Büsingen am Hochrhein", null], - ["083355002026", "Gailingen am Hochrhein", null], - ["083355002028", "Gottmadingen", null], - ["083355003025", "Gaienhofen", null], - ["083355003055", "Moos", null], - ["083355003061", "Öhningen", null], - ["083355004002", "Allensbach", null], - ["083355004043", "Konstanz, Universitätsstadt", null], - ["083355004066", "Reichenau", null], - ["083355005075", "Singen (Hohentwiel), Stadt", null], - ["083355005077", "Steißlingen", null], - ["083355005081", "Volkertshausen", null], - ["083355005100", "Rielasingen-Worblingen", null], - ["083355006021", "Eigeltingen", null], - ["083355006057", "Mühlingen", null], - ["083355006079", "Stockach, Stadt", null], - ["083355006096", "Hohenfels", null], - ["083355006098", "Bodman-Ludwigshafen", null], - ["083355006099", "Orsingen-Nenzingen", null], - ["083360014014", "Efringen-Kirchen", null], - ["083360084084", "Steinen", null], - ["083360087087", "Todtnau, Stadt", null], - ["083360091091", "Weil am Rhein, Stadt", null], - ["083360105105", "Grenzach-Wyhlen", null], - ["083360107107", "Kleines Wiesental", null], - ["083365001045", "Kandern, Stadt", null], - ["083365001104", "Malsburg-Marzell", null], - ["083365003043", "Inzlingen", null], - ["083365003050", "Lörrach, Stadt", null], - ["083365004069", "Rheinfelden (Baden), Stadt", null], - ["083365004082", "Schwörstadt", null], - ["083365005006", "Bad Bellingen", null], - ["083365005078", "Schliengen", null], - ["083365006004", "Aitern", null], - ["083365006010", "Böllen", null], - ["083365006025", "Fröhnd", null], - ["083365006079", "Schönau im Schwarzwald, Stadt", null], - ["083365006080", "Schönenberg", null], - ["083365006089", "Tunau", null], - ["083365006090", "Utzenfeld", null], - ["083365006094", "Wembach", null], - ["083365006096", "Wieden", null], - ["083365007034", "Hasel", null], - ["083365007036", "Hausen im Wiesental", null], - ["083365007057", "Maulburg", null], - ["083365007081", "Schopfheim, Stadt", null], - ["083365008008", "Binzen", null], - ["083365008019", "Eimeldingen", null], - ["083365008024", "Fischingen", null], - ["083365008073", "Rümmingen", null], - ["083365008075", "Schallbach", null], - ["083365008100", "Wittlingen", null], - ["083365009103", "Zell im Wiesental, Stadt", null], - ["083365009106", "Häg-Ehrsberg", null], - ["083370002002", "Albbruck", null], - ["083370038038", "Görwihl", null], - ["083370062062", "Klettgau", null], - ["083370066066", "Laufenburg (Baden), Stadt", null], - ["083370106106", "Stühlingen, Stadt", null], - ["083370116116", "Wehr, Stadt", null], - ["083375001022", "Bonndorf im Schwarzwald, Stadt", null], - ["083375001127", "Wutach", null], - ["083375002030", "Dettighofen", null], - ["083375002060", "Jestetten", null], - ["083375002070", "Lottstetten", null], - ["083375003053", "Hohentengen am Hochrhein", null], - ["083375003125", "Küssaberg", null], - ["083375004039", "Grafenhausen", null], - ["083375004128", "Ühlingen-Birkendorf", null], - ["083375005049", "Herrischried", null], - ["083375005076", "Murg", null], - ["083375005090", "Rickenbach", null], - ["083375005096", "Bad Säckingen, Stadt", null], - ["083375006013", "Bernau im Schwarzwald", null], - ["083375006027", "Dachsberg (Südschwarzwald)", null], - ["083375006045", "Häusern", null], - ["083375006051", "Höchenschwand", null], - ["083375006059", "Ibach", null], - ["083375006097", "St. Blasien, Stadt", null], - ["083375006108", "Todtmoos", null], - ["083375007032", "Dogern", null], - ["083375007065", "Lauchringen", null], - ["083375007118", "Weilheim", null], - ["083375007126", "Waldshut-Tiengen, Stadt", null], - ["083375008123", "Wutöschingen", null], - ["083375008124", "Eggingen", null], - ["084150014014", "Dettingen an der Erms", null], - ["084150019019", "Eningen unter Achalm", null], - ["084150059059", "Pfullingen, Stadt", null], - ["084150061061", "Reutlingen, Stadt", null], - ["084150073073", "Trochtelfingen, Stadt", null], - ["084150080080", "Wannweil", null], - ["084150091091", "Sonnenbühl", null], - ["084150092092", "Lichtenstein", null], - ["084150093093", "St. Johann", null], - ["084155001089", "Engstingen", null], - ["084155001090", "Hohenstein", null], - ["084155002029", "Grafenberg", null], - ["084155002050", "Metzingen, Stadt", null], - ["084155002062", "Riederich", null], - ["084155003027", "Gomadingen", null], - ["084155003048", "Mehrstetten", null], - ["084155003053", "Münsingen, Stadt", null], - ["084155004060", "Pliezhausen", null], - ["084155004087", "Walddorfhäslach", null], - ["084155005028", "Grabenstetten", null], - ["084155005039", "Hülben", null], - ["084155005078", "Bad Urach, Stadt", null], - ["084155005088", "Römerstein", null], - ["084155006034", "Hayingen, Stadt", null], - ["084155006058", "Pfronstetten", null], - ["084155006085", "Zwiefalten", null], - ["084159971971", "Gutsbezirk Münsingen, gemeindefreies Gebiet", null], - ["084160009009", "Dettenhausen", null], - ["084160022022", "Kirchentellinsfurt", null], - ["084160023023", "Kusterdingen", null], - ["084160041041", "Tübingen, Universitätsstadt", null], - ["084160048048", "Ammerbuch", null], - ["084165001011", "Dußlingen", null], - ["084165001015", "Gomaringen", null], - ["084165001026", "Nehren", null], - ["084165002006", "Bodelshausen", null], - ["084165002025", "Mössingen, Stadt", null], - ["084165002031", "Ofterdingen", null], - ["084165003018", "Hirrlingen", null], - ["084165003036", "Rottenburg am Neckar, Stadt", null], - ["084165003049", "Neustetten", null], - ["084165003050", "Starzach", null], - ["084170013013", "Burladingen, Stadt", null], - ["084170025025", "Haigerloch, Stadt", null], - ["084170054054", "Rosenfeld, Stadt", null], - ["084175001010", "Bitz", null], - ["084175001079", "Albstadt, Stadt", null], - ["084175002002", "Balingen, Stadt", null], - ["084175002022", "Geislingen, Stadt", null], - ["084175003008", "Bisingen", null], - ["084175003023", "Grosselfingen", null], - ["084175004031", "Hechingen, Stadt", null], - ["084175004036", "Jungingen", null], - ["084175004051", "Rangendingen", null], - ["084175005044", "Meßstetten, Stadt", null], - ["084175005045", "Nusplingen", null], - ["084175005047", "Obernheim", null], - ["084175006014", "Dautmergen", null], - ["084175006015", "Dormettingen", null], - ["084175006016", "Dotternhausen", null], - ["084175006029", "Hausen am Tann", null], - ["084175006052", "Ratshausen", null], - ["084175006057", "Schömberg, Stadt", null], - ["084175006071", "Weilen unter den Rinnen", null], - ["084175006078", "Zimmern unter der Burg", null], - ["084175007063", "Straßberg", null], - ["084175007075", "Winterlingen", null], - ["084210000000", "Ulm, Universitätsstadt", null], - ["084250039039", "Erbach, Stadt", null], - ["084250108108", "Schelklingen, Stadt", null], - ["084250141141", "Blaustein, Stadt", null], - ["084255001002", "Allmendingen", null], - ["084255001004", "Altheim", null], - ["084255002017", "Berghülen", null], - ["084255002020", "Blaubeuren, Stadt", null], - ["084255003028", "Dietenheim, Stadt", null], - ["084255003066", "Illerrieden", null], - ["084255003140", "Balzheim", null], - ["084255004014", "Beimerstetten", null], - ["084255004031", "Dornstadt", null], - ["084255004135", "Westerstetten", null], - ["084255005033", "Ehingen (Donau), Stadt", null], - ["084255005050", "Griesingen", null], - ["084255005088", "Oberdischingen", null], - ["084255005093", "Öpfingen", null], - ["084255006064", "Hüttisheim", null], - ["084255006110", "Schnürpflingen", null], - ["084255006137", "Illerkirchberg", null], - ["084255006138", "Staig", null], - ["084255007071", "Laichingen, Stadt", null], - ["084255007079", "Merklingen", null], - ["084255007084", "Nellingen", null], - ["084255007134", "Westerheim", null], - ["084255007139", "Heroldstatt", null], - ["084255008005", "Altheim (Alb)", null], - ["084255008011", "Asselfingen", null], - ["084255008013", "Ballendorf", null], - ["084255008019", "Bernstadt", null], - ["084255008022", "Börslingen", null], - ["084255008024", "Breitingen", null], - ["084255008062", "Holzkirch", null], - ["084255008072", "Langenau, Stadt", null], - ["084255008083", "Neenstetten", null], - ["084255008085", "Nerenstetten", null], - ["084255008092", "Öllingen", null], - ["084255008097", "Rammingen", null], - ["084255008112", "Setzingen", null], - ["084255008130", "Weidenstetten", null], - ["084255009008", "Amstetten", null], - ["084255009075", "Lonsee", null], - ["084255010035", "Emeringen", null], - ["084255010036", "Emerkingen", null], - ["084255010052", "Grundsheim", null], - ["084255010055", "Hausen am Bussen", null], - ["084255010073", "Lauterach", null], - ["084255010081", "Munderkingen, Stadt", null], - ["084255010090", "Obermarchtal", null], - ["084255010091", "Oberstadion", null], - ["084255010098", "Rechtenstein", null], - ["084255010104", "Rottenacker", null], - ["084255010123", "Untermarchtal", null], - ["084255010124", "Unterstadion", null], - ["084255010125", "Unterwachingen", null], - ["084260134134", "Schemmerhofen", null], - ["084265001005", "Alleshausen", null], - ["084265001006", "Allmannsweiler", null], - ["084265001013", "Bad Buchau, Stadt", null], - ["084265001020", "Betzenweiler", null], - ["084265001036", "Dürnau", null], - ["084265001064", "Kanzach", null], - ["084265001078", "Moosburg", null], - ["084265001090", "Oggelshausen", null], - ["084265001109", "Seekirch", null], - ["084265001118", "Tiefenbach", null], - ["084265002014", "Bad Schussenried, Stadt", null], - ["084265002062", "Ingoldingen", null], - ["084265003011", "Attenweiler", null], - ["084265003021", "Biberach an der Riß, Stadt", null], - ["084265003038", "Eberhardzell", null], - ["084265003058", "Hochdorf", null], - ["084265003071", "Maselheim", null], - ["084265003074", "Mittelbiberach", null], - ["084265003120", "Ummendorf", null], - ["084265003128", "Warthausen", null], - ["084265004019", "Berkheim", null], - ["084265004031", "Dettingen an der Iller", null], - ["084265004044", "Erolzheim", null], - ["084265004065", "Kirchberg an der Iller", null], - ["084265004066", "Kirchdorf an der Iller", null], - ["084265005001", "Achstetten", null], - ["084265005028", "Burgrieden", null], - ["084265005070", "Laupheim, Stadt", null], - ["084265005073", "Mietingen", null], - ["084265006043", "Erlenmoos", null], - ["084265006087", "Ochsenhausen, Stadt", null], - ["084265006113", "Steinhausen an der Rottum", null], - ["084265006135", "Gutenzell-Hürbel", null], - ["084265007008", "Altheim", null], - ["084265007035", "Dürmentingen", null], - ["084265007045", "Ertingen", null], - ["084265007067", "Langenenslingen", null], - ["084265007097", "Riedlingen, Stadt", null], - ["084265007121", "Unlingen", null], - ["084265007124", "Uttenweiler", null], - ["084265008100", "Rot an der Rot", null], - ["084265008117", "Tannheim", null], - ["084265009108", "Schwendi", null], - ["084265009125", "Wain", null], - ["084350035035", "Meckenbeuren", null], - ["084355001013", "Eriskirch", null], - ["084355001029", "Kressbronn am Bodensee", null], - ["084355001030", "Langenargen", null], - ["084355002016", "Friedrichshafen, Stadt", null], - ["084355002024", "Immenstaad am Bodensee", null], - ["084355003005", "Bermatingen", null], - ["084355003034", "Markdorf, Stadt", null], - ["084355003045", "Oberteuringen", null], - ["084355003067", "Deggenhausertal", null], - ["084355004010", "Daisendorf", null], - ["084355004018", "Hagnau am Bodensee", null], - ["084355004036", "Meersburg, Stadt", null], - ["084355004054", "Stetten", null], - ["084355004066", "Uhldingen-Mühlhofen", null], - ["084355005015", "Frickingen", null], - ["084355005020", "Heiligenberg", null], - ["084355005052", "Salem", null], - ["084355006042", "Neukirch", null], - ["084355006057", "Tettnang, Stadt", null], - ["084355007047", "Owingen", null], - ["084355007053", "Sipplingen", null], - ["084355007059", "Überlingen, Stadt", null], - ["084360008008", "Aulendorf, Stadt", null], - ["084360010010", "Bad Wurzach, Stadt", null], - ["084360049049", "Isny im Allgäu, Stadt", null], - ["084360052052", "Kißlegg", null], - ["084360094094", "Argenbühl", null], - ["084365001005", "Altshausen", null], - ["084365001019", "Boms", null], - ["084365001024", "Ebenweiler", null], - ["084365001027", "Eichstegen", null], - ["084365001032", "Fleischwangen", null], - ["084365001040", "Guggenhausen", null], - ["084365001047", "Hoßkirch", null], - ["084365001053", "Königseggwald", null], - ["084365001067", "Riedhausen", null], - ["084365001077", "Unterwaldhausen", null], - ["084365001093", "Ebersbach-Musbach", null], - ["084365002009", "Bad Waldsee, Stadt", null], - ["084365002014", "Bergatreute", null], - ["084365003018", "Bodnegg", null], - ["084365003039", "Grünkraut", null], - ["084365003069", "Schlier", null], - ["084365003079", "Waldburg", null], - ["084365004003", "Aichstetten", null], - ["084365004004", "Aitrach", null], - ["084365004055", "Leutkirch im Allgäu, Stadt", null], - ["084365005011", "Baienfurt", null], - ["084365005012", "Baindt", null], - ["084365005013", "Berg", null], - ["084365005064", "Ravensburg, Stadt", null], - ["084365005082", "Weingarten, Stadt", null], - ["084365006078", "Vogt", null], - ["084365006085", "Wolfegg", null], - ["084365007001", "Achberg", null], - ["084365007006", "Amtzell", null], - ["084365007081", "Wangen im Allgäu, Stadt", null], - ["084365008083", "Wilhelmsdorf", null], - ["084365008095", "Horgenzell", null], - ["084365009087", "Wolpertswende", null], - ["084365009096", "Fronreute", null], - ["084370086086", "Ostrach", null], - ["084375001031", "Gammertingen, Stadt", null], - ["084375001047", "Hettingen, Stadt", null], - ["084375001082", "Neufra", null], - ["084375001114", "Veringenstadt, Stadt", null], - ["084375002053", "Hohentengen", null], - ["084375002076", "Mengen, Stadt", null], - ["084375002101", "Scheer, Stadt", null], - ["084375003072", "Leibertingen", null], - ["084375003078", "Meßkirch, Stadt", null], - ["084375003123", "Sauldorf", null], - ["084375004056", "Illmensee", null], - ["084375004088", "Pfullendorf, Stadt", null], - ["084375004118", "Wald", null], - ["084375004124", "Herdwangen-Schönach", null], - ["084375005044", "Herbertingen", null], - ["084375005100", "Bad Saulgau, Stadt", null], - ["084375006005", "Beuron", null], - ["084375006008", "Bingen", null], - ["084375006059", "Inzigkofen", null], - ["084375006065", "Krauchenwies", null], - ["084375006104", "Sigmaringen, Stadt", null], - ["084375006105", "Sigmaringendorf", null], - ["084375007102", "Schwenningen", null], - ["084375007107", "Stetten am kalten Markt", null], - ["091610000000", "Ingolstadt", null], - ["091620000000", "München, Landeshauptstadt", null], - ["091630000000", "Rosenheim", null], - ["091710111111", "Altötting, St", null], - ["091710112112", "Burghausen, St", null], - ["091710113113", "Burgkirchen a.d.Alz", null], - ["091710117117", "Garching a.d.Alz", null], - ["091710118118", "Haiming", null], - ["091710125125", "Neuötting, St", null], - ["091710127127", "Pleiskirchen", null], - ["091710131131", "Teising", null], - ["091710132132", "Töging a.Inn, St", null], - ["091710133133", "Tüßling, M", null], - ["091710137137", "Winhöring", null], - ["091715101114", "Emmerting", null], - ["091715101124", "Mehring", null], - ["091715102116", "Feichten a.d.Alz", null], - ["091715102119", "Halsbach", null], - ["091715102122", "Kirchweidach", null], - ["091715102134", "Tyrlaching", null], - ["091715103123", "Marktl, M", null], - ["091715103130", "Stammham", null], - ["091715104115", "Erlbach", null], - ["091715104126", "Perach", null], - ["091715104129", "Reischach", null], - ["091715106121", "Kastl", null], - ["091715106135", "Unterneukirchen", null], - ["091720111111", "Ainring", null], - ["091720112112", "Anger", null], - ["091720114114", "Bad Reichenhall, GKSt", null], - ["091720115115", "Bayerisch Gmain", null], - ["091720116116", "Berchtesgaden, M", null], - ["091720117117", "Bischofswiesen", null], - ["091720118118", "Freilassing, St", null], - ["091720122122", "Laufen, St", null], - ["091720124124", "Marktschellenberg, M", null], - ["091720128128", "Piding", null], - ["091720129129", "Ramsau b.Berchtesgaden", null], - ["091720130130", "Saaldorf-Surheim", null], - ["091720131131", "Schneizlreuth", null], - ["091720132132", "Schönau a.Königssee", null], - ["091720134134", "Teisendorf, M", null], - ["091729452452", "Eck", null], - ["091729454454", "Schellenberger Forst", null], - ["091730111111", "Bad Heilbrunn", null], - ["091730112112", "Bad Tölz, St", null], - ["091730118118", "Dietramszell", null], - ["091730120120", "Egling", null], - ["091730123123", "Eurasburg", null], - ["091730124124", "Gaißach", null], - ["091730126126", "Geretsried, St", null], - ["091730130130", "Icking", null], - ["091730131131", "Jachenau", null], - ["091730134134", "Königsdorf", null], - ["091730135135", "Lenggries", null], - ["091730137137", "Münsing", null], - ["091730145145", "Wackersberg", null], - ["091730147147", "Wolfratshausen, St", null], - ["091735107113", "Benediktbeuern", null], - ["091735107115", "Bichl", null], - ["091735108133", "Kochel a.See", null], - ["091735108142", "Schlehdorf", null], - ["091735109127", "Greiling", null], - ["091735109140", "Reichersbeuern", null], - ["091735109141", "Sachsenkam", null], - ["091739451451", "Pupplinger Au", null], - ["091739452452", "Wolfratshauser Forst", null], - ["091740111111", "Altomünster, M", null], - ["091740113113", "Bergkirchen", null], - ["091740115115", "Dachau, GKSt", null], - ["091740118118", "Erdweg", null], - ["091740121121", "Haimhausen", null], - ["091740122122", "Hebertshausen", null], - ["091740126126", "Karlsfeld", null], - ["091740131131", "Markt Indersdorf, M", null], - ["091740135135", "Odelzhausen", null], - ["091740136136", "Petershausen", null], - ["091740137137", "Pfaffenhofen a.d.Glonn", null], - ["091740141141", "Röhrmoos", null], - ["091740143143", "Schwabhausen", null], - ["091740146146", "Sulzemoos", null], - ["091740147147", "Hilgertshausen-Tandern", null], - ["091740150150", "Vierkirchen", null], - ["091740151151", "Weichs", null], - ["091750111111", "Anzing", null], - ["091750115115", "Ebersberg, St", null], - ["091750118118", "Forstinning", null], - ["091750122122", "Grafing b.München, St", null], - ["091750123123", "Hohenlinden", null], - ["091750124124", "Kirchseeon, M", null], - ["091750127127", "Markt Schwaben, M", null], - ["091750132132", "Vaterstetten", null], - ["091750133133", "Pliening", null], - ["091750135135", "Poing", null], - ["091750137137", "Steinhöring", null], - ["091750139139", "Zorneding", null], - ["091755112112", "Aßling", null], - ["091755112119", "Frauenneuharting", null], - ["091755112136", "Emmering", null], - ["091755114113", "Baiern", null], - ["091755114114", "Bruck", null], - ["091755114116", "Egmating", null], - ["091755114121", "Glonn, M", null], - ["091755114128", "Moosach", null], - ["091755114131", "Oberpframmern", null], - ["091759451451", "Anzinger Forst", null], - ["091759452452", "Ebersberger Forst", null], - ["091759453453", "Eglhartinger Forst", null], - ["091760112112", "Altmannstein, M", null], - ["091760114114", "Beilngries, St", null], - ["091760118118", "Buxheim", null], - ["091760120120", "Denkendorf", null], - ["091760121121", "Dollnstein, M", null], - ["091760123123", "Eichstätt, GKSt", null], - ["091760126126", "Gaimersheim, M", null], - ["091760129129", "Großmehring", null], - ["091760131131", "Hepberg", null], - ["091760132132", "Hitzhofen", null], - ["091760137137", "Kinding, M", null], - ["091760138138", "Kipfenberg, M", null], - ["091760139139", "Kösching, M", null], - ["091760143143", "Lenting", null], - ["091760148148", "Mörnsheim, M", null], - ["091760161161", "Stammham", null], - ["091760164164", "Titting, M", null], - ["091760166166", "Wellheim, M", null], - ["091760167167", "Wettstetten", null], - ["091765115155", "Pollenfeld", null], - ["091765115160", "Schernfeld", null], - ["091765115165", "Walting", null], - ["091765116116", "Böhmfeld", null], - ["091765116124", "Eitensheim", null], - ["091765118111", "Adelschlag", null], - ["091765118122", "Egweil", null], - ["091765118149", "Nassenfels, M", null], - ["091765119147", "Mindelstetten", null], - ["091765119150", "Oberdolling", null], - ["091765119153", "Pförring, M", null], - ["091769451451", "Haunstetter Forst", null], - ["091770113113", "Bockhorn", null], - ["091770115115", "Dorfen, St", null], - ["091770117117", "Erding, GKSt", null], - ["091770118118", "Finsing", null], - ["091770119119", "Forstern", null], - ["091770120120", "Fraunberg", null], - ["091770123123", "Isen, M", null], - ["091770127127", "Lengdorf", null], - ["091770130130", "Moosinning", null], - ["091770137137", "Sankt Wolfgang", null], - ["091770139139", "Taufkirchen (Vils)", null], - ["091775120114", "Buch a.Buchrain", null], - ["091775120135", "Pastetten", null], - ["091775121142", "Walpertskirchen", null], - ["091775121144", "Wörth", null], - ["091775123116", "Eitting", null], - ["091775123133", "Oberding", null], - ["091775124131", "Neuching", null], - ["091775124134", "Ottenhofen", null], - ["091775125121", "Hohenpolding", null], - ["091775125122", "Inning a.Holz", null], - ["091775125124", "Kirchberg", null], - ["091775125138", "Steinkirchen", null], - ["091775126112", "Berglern", null], - ["091775126126", "Langenpreising", null], - ["091775126143", "Wartenberg, M", null], - ["091780116116", "Au i.d.Hallertau, M", null], - ["091780120120", "Eching", null], - ["091780122122", "Rudelzhausen", null], - ["091780123123", "Fahrenzhausen", null], - ["091780124124", "Freising, GKSt", null], - ["091780130130", "Hallbergmoos", null], - ["091780133133", "Hohenkammer", null], - ["091780136136", "Kirchdorf a.d.Amper", null], - ["091780137137", "Kranzberg", null], - ["091780138138", "Langenbach", null], - ["091780140140", "Marzling", null], - ["091780143143", "Moosburg a.d.Isar, St", null], - ["091780144144", "Nandlstadt, M", null], - ["091780145145", "Neufahrn b.Freising", null], - ["091785127113", "Allershausen", null], - ["091785127150", "Paunzhausen", null], - ["091785129125", "Gammelsdorf", null], - ["091785129132", "Hörgertshausen", null], - ["091785129142", "Mauern", null], - ["091785129155", "Wang", null], - ["091785130115", "Attenkirchen", null], - ["091785130129", "Haag a.d.Amper", null], - ["091785130156", "Wolfersdorf", null], - ["091785130157", "Zolling", null], - ["091790113113", "Alling", null], - ["091790117117", "Egenhofen", null], - ["091790118118", "Eichenau", null], - ["091790119119", "Emmering", null], - ["091790121121", "Fürstenfeldbruck, GKSt", null], - ["091790123123", "Germering, GKSt", null], - ["091790126126", "Gröbenzell", null], - ["091790134134", "Maisach", null], - ["091790138138", "Moorenweis", null], - ["091790142142", "Olching, St", null], - ["091790145145", "Puchheim, St", null], - ["091790149149", "Türkenfeld", null], - ["091795131111", "Adelshofen", null], - ["091795131114", "Althegnenberg", null], - ["091795131128", "Hattenhofen", null], - ["091795131130", "Jesenwang", null], - ["091795131132", "Landsberied", null], - ["091795131136", "Mammendorf", null], - ["091795131137", "Mittelstetten", null], - ["091795131140", "Oberschweinbach", null], - ["091795132125", "Grafrath", null], - ["091795132131", "Kottgeisering", null], - ["091795132147", "Schöngeising", null], - ["091800112112", "Bad Kohlgrub", null], - ["091800116116", "Farchant", null], - ["091800117117", "Garmisch-Partenkirchen, M", null], - ["091800118118", "Grainau", null], - ["091800122122", "Krün", null], - ["091800123123", "Mittenwald, M", null], - ["091800124124", "Murnau a.Staffelsee, M", null], - ["091800125125", "Oberammergau", null], - ["091800126126", "Oberau", null], - ["091800134134", "Uffing a.Staffelsee", null], - ["091800136136", "Wallgau", null], - ["091805133113", "Bad Bayersoien", null], - ["091805133129", "Saulgrub", null], - ["091805135115", "Ettal", null], - ["091805135135", "Unterammergau", null], - ["091805136114", "Eschenlohe", null], - ["091805136119", "Großweil", null], - ["091805136127", "Ohlstadt", null], - ["091805136131", "Schwaigen", null], - ["091805137128", "Riegsee", null], - ["091805137132", "Seehausen a.Staffelsee", null], - ["091805137133", "Spatzenhausen", null], - ["091809451451", "Ettaler Forst", null], - ["091810113113", "Denklingen", null], - ["091810114114", "Dießen am Ammersee, M", null], - ["091810116116", "Egling a.d.Paar", null], - ["091810122122", "Geltendorf", null], - ["091810128128", "Kaufering, M", null], - ["091810130130", "Landsberg am Lech, GKSt", null], - ["091810132132", "Penzing", null], - ["091810144144", "Utting am Ammersee", null], - ["091810145145", "Weil", null], - ["091815138121", "Fuchstal", null], - ["091815138143", "Unterdießen", null], - ["091815139126", "Hurlach", null], - ["091815139127", "Igling", null], - ["091815139131", "Obermeitingen", null], - ["091815140134", "Prittriching", null], - ["091815140138", "Scheuring", null], - ["091815141124", "Hofstetten", null], - ["091815141140", "Schwifting", null], - ["091815141141", "Pürgen", null], - ["091815142111", "Apfeldorf", null], - ["091815142129", "Kinsau", null], - ["091815142133", "Vilgertshofen", null], - ["091815142135", "Reichling", null], - ["091815142137", "Rott", null], - ["091815142142", "Thaining", null], - ["091815143115", "Eching am Ammersee", null], - ["091815143123", "Greifenberg", null], - ["091815143139", "Schondorf am Ammersee", null], - ["091815144118", "Eresing", null], - ["091815144120", "Finning", null], - ["091815144146", "Windach", null], - ["091819451451", "Ammersee", null], - ["091820111111", "Bad Wiessee", null], - ["091820112112", "Bayrischzell", null], - ["091820114114", "Fischbachau", null], - ["091820116116", "Gmund a.Tegernsee", null], - ["091820119119", "Hausham", null], - ["091820120120", "Holzkirchen, M", null], - ["091820123123", "Irschenberg", null], - ["091820124124", "Kreuth", null], - ["091820125125", "Miesbach, St", null], - ["091820127127", "Otterfing", null], - ["091820129129", "Rottach-Egern", null], - ["091820131131", "Schliersee, M", null], - ["091820132132", "Tegernsee, St", null], - ["091820133133", "Valley", null], - ["091820134134", "Waakirchen", null], - ["091820136136", "Warngau", null], - ["091820137137", "Weyarn", null], - ["091830112112", "Ampfing", null], - ["091830113113", "Aschau a.Inn", null], - ["091830114114", "Buchbach, M", null], - ["091830119119", "Haag i.OB, M", null], - ["091830127127", "Mettenheim", null], - ["091830128128", "Mühldorf a.Inn, St", null], - ["091830135135", "Obertaufkirchen", null], - ["091830144144", "Schwindegg", null], - ["091830148148", "Waldkraiburg, St", null], - ["091835145120", "Heldenstein", null], - ["091835145138", "Rattenkirchen", null], - ["091835146118", "Gars a.Inn, M", null], - ["091835146147", "Unterreit", null], - ["091835147123", "Kirchdorf", null], - ["091835147140", "Reichertsheim", null], - ["091835148122", "Jettenbach", null], - ["091835148124", "Kraiburg a.Inn, M", null], - ["091835148145", "Taufkirchen", null], - ["091835149115", "Egglkofen", null], - ["091835149129", "Neumarkt-Sankt Veit, St", null], - ["091835150125", "Lohkirchen", null], - ["091835150132", "Oberbergkirchen", null], - ["091835150143", "Schönberg", null], - ["091835150151", "Zangberg", null], - ["091835151134", "Oberneukirchen", null], - ["091835151136", "Polling", null], - ["091835152116", "Erharting", null], - ["091835152130", "Niederbergkirchen", null], - ["091835152131", "Niedertaufkirchen", null], - ["091835183126", "Maitenbeth", null], - ["091835183139", "Rechtmehring", null], - ["091839451451", "Mühldorfer Hart", null], - ["091840112112", "Aschheim", null], - ["091840113113", "Baierbrunn", null], - ["091840114114", "Brunnthal", null], - ["091840118118", "Feldkirchen", null], - ["091840119119", "Garching b.München, St", null], - ["091840120120", "Gräfelfing", null], - ["091840121121", "Grasbrunn", null], - ["091840122122", "Grünwald", null], - ["091840123123", "Haar", null], - ["091840127127", "Höhenkirchen-Siegertsbrunn", null], - ["091840129129", "Hohenbrunn", null], - ["091840130130", "Ismaning", null], - ["091840131131", "Kirchheim b.München", null], - ["091840132132", "Neuried", null], - ["091840134134", "Oberhaching", null], - ["091840135135", "Oberschleißheim", null], - ["091840136136", "Ottobrunn", null], - ["091840137137", "Aying", null], - ["091840138138", "Planegg", null], - ["091840139139", "Pullach i.Isartal", null], - ["091840140140", "Putzbrunn", null], - ["091840141141", "Sauerlach", null], - ["091840142142", "Schäftlarn", null], - ["091840144144", "Straßlach-Dingharting", null], - ["091840145145", "Taufkirchen", null], - ["091840146146", "Neubiberg", null], - ["091840147147", "Unterföhring", null], - ["091840148148", "Unterhaching", null], - ["091840149149", "Unterschleißheim, St", null], - ["091849452452", "Forstenrieder Park", null], - ["091849454454", "Grünwalder Forst", null], - ["091849457457", "Perlacher Forst", null], - ["091850113113", "Aresing", null], - ["091850125125", "Burgheim, M", null], - ["091850127127", "Ehekirchen", null], - ["091850139139", "Karlshuld", null], - ["091850140140", "Karlskron", null], - ["091850149149", "Neuburg a.d.Donau, GKSt", null], - ["091850150150", "Oberhausen", null], - ["091850153153", "Rennertshofen, M", null], - ["091850158158", "Schrobenhausen, St", null], - ["091850163163", "Königsmoos", null], - ["091850168168", "Weichering", null], - ["091855154118", "Bergheim", null], - ["091855154157", "Rohrenfels", null], - ["091855155116", "Berg im Gau", null], - ["091855155123", "Brunnen", null], - ["091855155131", "Gachenbach", null], - ["091855155143", "Langenmosen", null], - ["091855155166", "Waidhofen", null], - ["091860113113", "Baar-Ebenhausen", null], - ["091860125125", "Gerolsbach", null], - ["091860128128", "Hohenwart, M", null], - ["091860132132", "Jetzendorf", null], - ["091860137137", "Manching, M", null], - ["091860139139", "Münchsmünster", null], - ["091860143143", "Pfaffenhofen a.d.Ilm, St", null], - ["091860146146", "Reichertshausen", null], - ["091860149149", "Rohrbach", null], - ["091860151151", "Scheyern", null], - ["091860152152", "Schweitenkirchen", null], - ["091860158158", "Vohburg a.d.Donau, St", null], - ["091860162162", "Wolnzach, M", null], - ["091865156116", "Ernsgaden", null], - ["091865156122", "Geisenfeld, St", null], - ["091865157126", "Hettenshausen", null], - ["091865157130", "Ilmmünster", null], - ["091865158144", "Pörnbach", null], - ["091865158147", "Reichertshofen, M", null], - ["091870113113", "Amerang", null], - ["091870114114", "Aschau i.Chiemgau", null], - ["091870116116", "Babensham", null], - ["091870117117", "Bad Aibling, St", null], - ["091870118118", "Bernau a.Chiemsee", null], - ["091870120120", "Brannenburg", null], - ["091870122122", "Bruckmühl, M", null], - ["091870124124", "Edling", null], - ["091870125125", "Eggstätt", null], - ["091870126126", "Eiselfing", null], - ["091870128128", "Bad Endorf, M", null], - ["091870129129", "Bad Feilnbach", null], - ["091870130130", "Feldkirchen-Westerham", null], - ["091870131131", "Flintsbach a.Inn", null], - ["091870132132", "Frasdorf", null], - ["091870134134", "Griesstätt", null], - ["091870137137", "Großkarolinenfeld", null], - ["091870142142", "Schechen", null], - ["091870148148", "Kiefersfelden", null], - ["091870150150", "Kolbermoor, St", null], - ["091870154154", "Neubeuern, M", null], - ["091870156156", "Nußdorf a.Inn", null], - ["091870157157", "Oberaudorf", null], - ["091870162162", "Prien a.Chiemsee, M", null], - ["091870163163", "Prutting", null], - ["091870165165", "Raubling", null], - ["091870167167", "Riedering", null], - ["091870168168", "Rimsting", null], - ["091870169169", "Rohrdorf", null], - ["091870172172", "Samerberg", null], - ["091870174174", "Söchtenau", null], - ["091870176176", "Soyen", null], - ["091870177177", "Stephanskirchen", null], - ["091870179179", "Tuntenhausen", null], - ["091870181181", "Vogtareuth", null], - ["091870182182", "Wasserburg a.Inn, St", null], - ["091875160121", "Breitbrunn a.Chiemsee", null], - ["091875160123", "Chiemsee", null], - ["091875160138", "Gstadt a.Chiemsee", null], - ["091875162139", "Halfing", null], - ["091875162145", "Höslwang", null], - ["091875162173", "Schonstett", null], - ["091875165164", "Ramerberg", null], - ["091875165170", "Rott a.Inn", null], - ["091875184159", "Pfaffing", null], - ["091875184186", "Albaching", null], - ["091879451451", "Rotter Forst-Nord", null], - ["091879452452", "Rotter Forst-Süd", null], - ["091880113113", "Berg", null], - ["091880117117", "Andechs", null], - ["091880118118", "Feldafing", null], - ["091880120120", "Gauting", null], - ["091880121121", "Gilching", null], - ["091880124124", "Herrsching a.Ammersee", null], - ["091880126126", "Inning a.Ammersee", null], - ["091880127127", "Krailling", null], - ["091880132132", "Seefeld", null], - ["091880137137", "Pöcking", null], - ["091880139139", "Starnberg, St", null], - ["091880141141", "Tutzing", null], - ["091880144144", "Weßling", null], - ["091880145145", "Wörthsee", null], - ["091889451451", "Starnberger See", null], - ["091890111111", "Altenmarkt a.d.Alz", null], - ["091890114114", "Chieming", null], - ["091890115115", "Engelsberg", null], - ["091890118118", "Fridolfing", null], - ["091890119119", "Grabenstätt", null], - ["091890120120", "Grassau, M", null], - ["091890124124", "Inzell", null], - ["091890127127", "Kirchanschöring", null], - ["091890130130", "Nußdorf", null], - ["091890134134", "Palling", null], - ["091890135135", "Petting", null], - ["091890139139", "Reit im Winkl", null], - ["091890140140", "Ruhpolding", null], - ["091890141141", "Schleching", null], - ["091890142142", "Schnaitsee", null], - ["091890143143", "Seeon-Seebruck", null], - ["091890145145", "Siegsdorf", null], - ["091890148148", "Surberg", null], - ["091890149149", "Tacherting", null], - ["091890152152", "Tittmoning, St", null], - ["091890154154", "Traunreut, St", null], - ["091890155155", "Traunstein, GKSt", null], - ["091890157157", "Trostberg, St", null], - ["091890159159", "Übersee", null], - ["091890160160", "Unterwössen", null], - ["091895166113", "Bergen", null], - ["091895166161", "Vachendorf", null], - ["091895169129", "Marquartstein", null], - ["091895169146", "Staudach-Egerndach", null], - ["091895170126", "Kienberg", null], - ["091895170133", "Obing", null], - ["091895170137", "Pittenhart", null], - ["091895173150", "Taching a.See", null], - ["091895173162", "Waging a.See, M", null], - ["091895173165", "Wonneberg", null], - ["091899451451", "Chiemsee (See)", null], - ["091899452452", "Waginger See", null], - ["091900115115", "Bernried am Starnberger See", null], - ["091900130130", "Hohenpeißenberg", null], - ["091900138138", "Pähl", null], - ["091900139139", "Peißenberg, M", null], - ["091900140140", "Peiting, M", null], - ["091900141141", "Penzberg, St", null], - ["091900142142", "Polling", null], - ["091900144144", "Raisting", null], - ["091900148148", "Schongau, St", null], - ["091900157157", "Weilheim i.OB, St", null], - ["091900158158", "Wessobrunn", null], - ["091900159159", "Wielenbach", null], - ["091905174111", "Altenstadt", null], - ["091905174129", "Hohenfurch", null], - ["091905174133", "Ingenried", null], - ["091905174149", "Schwabbruck", null], - ["091905174151", "Schwabsoien", null], - ["091905175114", "Bernbeuren", null], - ["091905175118", "Burggen", null], - ["091905176113", "Antdorf", null], - ["091905176126", "Habach", null], - ["091905176136", "Obersöchering", null], - ["091905176153", "Sindelsdorf", null], - ["091905177120", "Eberfing", null], - ["091905177121", "Eglfing", null], - ["091905177131", "Huglfing", null], - ["091905177135", "Oberhausen", null], - ["091905178117", "Böbing", null], - ["091905178145", "Rottenbuch", null], - ["091905179132", "Iffeldorf", null], - ["091905179152", "Seeshaupt", null], - ["091905180143", "Prem", null], - ["091905180154", "Steingaden", null], - ["091905180160", "Wildsteig", null], - ["092610000000", "Landshut", null], - ["092620000000", "Passau", null], - ["092630000000", "Straubing", null], - ["092710111111", "Aholming", null], - ["092710113113", "Auerbach", null], - ["092710116116", "Bernried", null], - ["092710119119", "Deggendorf, GKSt", null], - ["092710122122", "Grafling", null], - ["092710125125", "Hengersberg, M", null], - ["092710127127", "Iggensbach", null], - ["092710128128", "Künzing", null], - ["092710132132", "Metten, M", null], - ["092710138138", "Niederalteich", null], - ["092710140140", "Offenberg", null], - ["092710141141", "Osterhofen, St", null], - ["092710146146", "Plattling, St", null], - ["092710151151", "Stephansposching", null], - ["092710153153", "Winzer, M", null], - ["092715202123", "Grattersdorf", null], - ["092715202126", "Hunding", null], - ["092715202130", "Lalling", null], - ["092715202148", "Schaufling", null], - ["092715204139", "Oberpöring", null], - ["092715204143", "Otzing", null], - ["092715204152", "Wallerfing", null], - ["092715205118", "Buchhofen", null], - ["092715205135", "Moos", null], - ["092715206114", "Außernzell", null], - ["092715206149", "Schöllnach, M", null], - ["092720118118", "Freyung, St", null], - ["092720120120", "Grafenau, St", null], - ["092720121121", "Grainet", null], - ["092720122122", "Haidmühle", null], - ["092720127127", "Hohenau", null], - ["092720129129", "Jandelsbrunn", null], - ["092720134134", "Mauth", null], - ["092720136136", "Neureichenau", null], - ["092720140140", "Ringelai", null], - ["092720141141", "Röhrnbach, M", null], - ["092720142142", "Saldenburg", null], - ["092720143143", "Sankt Oswald-Riedlhütte", null], - ["092720146146", "Neuschönau", null], - ["092720149149", "Spiegelau", null], - ["092720151151", "Waldkirchen, St", null], - ["092725211116", "Eppenschlag", null], - ["092725211128", "Innernzell", null], - ["092725211145", "Schöfweg", null], - ["092725211147", "Schönberg, M", null], - ["092725212126", "Hinterschmiding", null], - ["092725212139", "Philippsreut", null], - ["092725213150", "Thurmansbang", null], - ["092725213152", "Zenting", null], - ["092725214119", "Fürsteneck", null], - ["092725214138", "Perlesreut, M", null], - ["092729451451", "Annathaler Wald", null], - ["092729452452", "Frauenberger u. Duschlberger Wald", null], - ["092729453453", "Graineter Wald", null], - ["092729455455", "Leopoldsreuter Wald", null], - ["092729456456", "Mauther Forst", null], - ["092729457457", "Philippsreuter Wald", null], - ["092729458458", "Pleckensteiner Wald", null], - ["092729459459", "Sankt Oswald", null], - ["092729460460", "Schlichtenberger Wald", null], - ["092729461461", "Schönbrunner Wald", null], - ["092729463463", "Waldhäuserwald", null], - ["092730111111", "Abensberg, St", null], - ["092730116116", "Bad Abbach, M", null], - ["092730137137", "Kelheim, St", null], - ["092730147147", "Mainburg, St", null], - ["092730152152", "Neustadt a.d.Donau, St", null], - ["092730159159", "Painten, M", null], - ["092730164164", "Riedenburg, St", null], - ["092730165165", "Rohr i.NB, M", null], - ["092735215121", "Essing, M", null], - ["092735215133", "Ihrlerstein", null], - ["092735216166", "Saal a.d.Donau", null], - ["092735216175", "Teugn", null], - ["092735217125", "Hausen", null], - ["092735217127", "Herrngiersdorf", null], - ["092735217141", "Langquaid, M", null], - ["092735218119", "Biburg", null], - ["092735218139", "Kirchdorf", null], - ["092735218172", "Siegenburg, M", null], - ["092735218177", "Train", null], - ["092735218181", "Wildenberg", null], - ["092735219113", "Aiglsbach", null], - ["092735219115", "Attenhofen", null], - ["092735219163", "Elsendorf", null], - ["092735219178", "Volkenschwand", null], - ["092739451451", "Dürnbucher Forst", null], - ["092739452452", "Frauenforst", null], - ["092739453453", "Hacklberg", null], - ["092739454454", "Hienheimer Forst", null], - ["092740111111", "Adlkofen", null], - ["092740113113", "Altdorf, M", null], - ["092740120120", "Bodenkirchen", null], - ["092740121121", "Buch a.Erlbach", null], - ["092740124124", "Eching", null], - ["092740126126", "Ergolding, M", null], - ["092740128128", "Essenbach, M", null], - ["092740134134", "Geisenhausen, M", null], - ["092740141141", "Hohenthann", null], - ["092740146146", "Kumhausen", null], - ["092740153153", "Neufahrn i.NB", null], - ["092740156156", "Niederaichbach", null], - ["092740172172", "Pfeffenhausen, M", null], - ["092740176176", "Rottenburg a.d.Laaber, St", null], - ["092740182182", "Tiefenbach", null], - ["092740184184", "Vilsbiburg, St", null], - ["092740185185", "Vilsheim", null], - ["092740194194", "Bruckberg", null], - ["092745220119", "Bayerbach b.Ergoldsbach", null], - ["092745220127", "Ergoldsbach, M", null], - ["092745221132", "Furth", null], - ["092745221165", "Obersüßbach", null], - ["092745221187", "Weihmichl", null], - ["092745222174", "Postau", null], - ["092745222188", "Weng", null], - ["092745222191", "Wörth a.d.Isar", null], - ["092745223112", "Aham", null], - ["092745223135", "Gerzen", null], - ["092745223145", "Kröning", null], - ["092745223179", "Schalkham", null], - ["092745226114", "Altfraunhofen", null], - ["092745226118", "Baierbach", null], - ["092745227154", "Neufraunhofen", null], - ["092745227183", "Velden, M", null], - ["092745227193", "Wurmsham", null], - ["092750111111", "Aicha vorm Wald", null], - ["092750114114", "Aldersbach", null], - ["092750116116", "Bad Füssing", null], - ["092750118118", "Breitenberg", null], - ["092750119119", "Büchlberg", null], - ["092750120120", "Eging a.See, M", null], - ["092750121121", "Fürstenstein", null], - ["092750122122", "Fürstenzell, M", null], - ["092750124124", "Bad Griesbach i.Rottal, St", null], - ["092750125125", "Haarbach", null], - ["092750126126", "Hauzenberg, St", null], - ["092750127127", "Hofkirchen, M", null], - ["092750128128", "Hutthurm, M", null], - ["092750130130", "Kirchham", null], - ["092750131131", "Kößlarn, M", null], - ["092750133133", "Neuburg a.Inn", null], - ["092750134134", "Neuhaus a.Inn", null], - ["092750135135", "Neukirchen vorm Wald", null], - ["092750137137", "Obernzell, M", null], - ["092750138138", "Ortenburg, M", null], - ["092750141141", "Pocking, St", null], - ["092750144144", "Ruderting", null], - ["092750145145", "Ruhstorf a.d.Rott, M", null], - ["092750146146", "Salzweg", null], - ["092750148148", "Sonnen", null], - ["092750149149", "Tettenweis", null], - ["092750150150", "Thyrnau", null], - ["092750151151", "Tiefenbach", null], - ["092750153153", "Untergriesbach, M", null], - ["092750154154", "Vilshofen an der Donau, St", null], - ["092750156156", "Wegscheid, M", null], - ["092750159159", "Windorf, M", null], - ["092755229152", "Tittling, M", null], - ["092755229160", "Witzmannsberg", null], - ["092755232112", "Aidenbach, M", null], - ["092755232117", "Beutelsbach", null], - ["092755234132", "Malching", null], - ["092755234143", "Rotthalmünster, M", null], - ["092760113113", "Arnbruck", null], - ["092760115115", "Bayerisch Eisenstein", null], - ["092760116116", "Bischofsmais", null], - ["092760117117", "Bodenmais, M", null], - ["092760118118", "Böbrach", null], - ["092760120120", "Drachselsried", null], - ["092760121121", "Frauenau", null], - ["092760122122", "Geiersthal", null], - ["092760126126", "Kirchberg i.Wald", null], - ["092760127127", "Kirchdorf i.Wald", null], - ["092760128128", "Kollnburg", null], - ["092760129129", "Langdorf", null], - ["092760130130", "Lindberg", null], - ["092760134134", "Patersdorf", null], - ["092760135135", "Prackenbach", null], - ["092760138138", "Regen, St", null], - ["092760139139", "Rinchnach", null], - ["092760143143", "Teisnach, M", null], - ["092760144144", "Viechtach, St", null], - ["092760148148", "Zwiesel, St", null], - ["092765238111", "Achslach", null], - ["092765238123", "Gotteszell", null], - ["092765238142", "Ruhmannsfelden, M", null], - ["092765238146", "Zachenberg", null], - ["092770111111", "Arnstorf, M", null], - ["092770114114", "Dietersburg", null], - ["092770116116", "Eggenfelden, St", null], - ["092770117117", "Egglham", null], - ["092770121121", "Gangkofen, M", null], - ["092770124124", "Hebertsfelden", null], - ["092770126126", "Johanniskirchen", null], - ["092770127127", "Julbach", null], - ["092770128128", "Kirchdorf a.Inn", null], - ["092770134134", "Mitterskirchen", null], - ["092770138138", "Pfarrkirchen, St", null], - ["092770139139", "Postmünster", null], - ["092770142142", "Roßbach", null], - ["092770144144", "Schönau", null], - ["092770145145", "Simbach a.Inn, St", null], - ["092770149149", "Triftern, M", null], - ["092770151151", "Unterdietfurt", null], - ["092770152152", "Wittibreut", null], - ["092770153153", "Wurmannsquick, M", null], - ["092770154154", "Zeilarn", null], - ["092775239119", "Falkenberg", null], - ["092775239131", "Malgersdorf", null], - ["092775239141", "Rimbach", null], - ["092775240122", "Geratskirchen", null], - ["092775240133", "Massing, M", null], - ["092775241112", "Bayerbach", null], - ["092775241113", "Bad Birnbach, M", null], - ["092775243140", "Reut", null], - ["092775243148", "Tann, M", null], - ["092775244118", "Ering", null], - ["092775244147", "Stubenberg", null], - ["092780118118", "Bogen, St", null], - ["092780121121", "Feldkirchen", null], - ["092780123123", "Geiselhöring, St", null], - ["092780129129", "Haibach", null], - ["092780141141", "Kirchroth", null], - ["092780143143", "Konzell", null], - ["092780144144", "Laberweinting", null], - ["092780146146", "Leiblfing", null], - ["092780148148", "Mallersdorf-Pfaffenberg, M", null], - ["092780167167", "Oberschneiding", null], - ["092780170170", "Parkstetten", null], - ["092780178178", "Rattenberg", null], - ["092780184184", "Sankt Englmar", null], - ["092780190190", "Steinach", null], - ["092780197197", "Wiesenfelden", null], - ["092785246147", "Loitzendorf", null], - ["092785246179", "Rattiszell", null], - ["092785246189", "Stallwang", null], - ["092785248116", "Ascha", null], - ["092785248120", "Falkenfels", null], - ["092785248134", "Haselbach", null], - ["092785248151", "Mitterfels, M", null], - ["092785249139", "Hunderdorf", null], - ["092785249154", "Neukirchen", null], - ["092785249198", "Windberg", null], - ["092785250112", "Aholfing", null], - ["092785250117", "Atting", null], - ["092785250172", "Perkam", null], - ["092785250177", "Rain", null], - ["092785252149", "Mariaposching", null], - ["092785252159", "Niederwinkling", null], - ["092785252171", "Perasdorf", null], - ["092785252187", "Schwarzach, M", null], - ["092785256113", "Aiterhofen", null], - ["092785256182", "Salching", null], - ["092785257140", "Irlbach", null], - ["092785257192", "Straßkirchen", null], - ["092790112112", "Dingolfing, St", null], - ["092790113113", "Eichendorf, M", null], - ["092790115115", "Frontenhausen, M", null], - ["092790122122", "Landau a.d.Isar, St", null], - ["092790124124", "Loiching", null], - ["092790126126", "Marklkofen", null], - ["092790127127", "Mengkofen", null], - ["092790128128", "Moosthenning", null], - ["092790130130", "Niederviehbach", null], - ["092790132132", "Pilsting, M", null], - ["092790134134", "Reisbach, M", null], - ["092790135135", "Simbach, M", null], - ["092790137137", "Wallersdorf, M", null], - ["092795208116", "Gottfrieding", null], - ["092795208125", "Mamming", null], - ["093610000000", "Amberg", null], - ["093620000000", "Regensburg", null], - ["093630000000", "Weiden i.d.OPf.", null], - ["093710111111", "Ammerthal", null], - ["093710113113", "Auerbach i.d.OPf., St", null], - ["093710118118", "Ebermannsdorf", null], - ["093710119119", "Edelsfeld", null], - ["093710120120", "Ensdorf", null], - ["093710121121", "Freihung, M", null], - ["093710122122", "Freudenberg", null], - ["093710127127", "Hirschau, St", null], - ["093710129129", "Hohenburg, M", null], - ["093710132132", "Kastl, M", null], - ["093710136136", "Kümmersbruck", null], - ["093710144144", "Poppenricht", null], - ["093710146146", "Rieden, M", null], - ["093710148148", "Schmidmühlen, M", null], - ["093710150150", "Schnaittenbach, St", null], - ["093710151151", "Sulzbach-Rosenberg, St", null], - ["093710154154", "Ursensollen", null], - ["093710156156", "Vilseck, St", null], - ["093715301123", "Gebenbach", null], - ["093715301126", "Hahnbach, M", null], - ["093715302128", "Hirschbach", null], - ["093715302135", "Königstein, M", null], - ["093715303140", "Etzelwang", null], - ["093715303141", "Neukirchen b.Sulzbach-Rosenberg", null], - ["093715303157", "Weigendorf", null], - ["093715304116", "Birgland", null], - ["093715304131", "Illschwang", null], - ["093719452452", "Eichen", null], - ["093720112112", "Arnschwang", null], - ["093720113113", "Arrach", null], - ["093720115115", "Blaibach", null], - ["093720116116", "Cham, St", null], - ["093720117117", "Chamerau", null], - ["093720124124", "Eschlkam, M", null], - ["093720126126", "Furth im Wald, St", null], - ["093720130130", "Grafenwiesen", null], - ["093720135135", "Hohenwarth", null], - ["093720137137", "Bad Kötzting, St", null], - ["093720138138", "Lam, M", null], - ["093720143143", "Miltach", null], - ["093720144144", "Neukirchen b.Hl.Blut, M", null], - ["093720146146", "Pemfling", null], - ["093720151151", "Rimbach", null], - ["093720153153", "Roding, St", null], - ["093720154154", "Rötz, St", null], - ["093720155155", "Runding", null], - ["093720157157", "Schönthal", null], - ["093720158158", "Schorndorf", null], - ["093720164164", "Traitsching", null], - ["093720168168", "Waffenbrunn", null], - ["093720171171", "Waldmünchen, St", null], - ["093720175175", "Willmering", null], - ["093720177177", "Zandt", null], - ["093720178178", "Lohberg", null], - ["093725308163", "Tiefenbach", null], - ["093725308165", "Treffelstein", null], - ["093725310147", "Pösing", null], - ["093725310161", "Stamsried, M", null], - ["093725312128", "Gleißenberg", null], - ["093725312174", "Weiding", null], - ["093725313149", "Reichenbach", null], - ["093725313170", "Walderbach", null], - ["093725317167", "Zell", null], - ["093725317169", "Wald", null], - ["093725318125", "Falkenstein, M", null], - ["093725318142", "Michelsneukirchen", null], - ["093725318150", "Rettenbach", null], - ["093730112112", "Berching, St", null], - ["093730113113", "Berg b.Neumarkt i.d.OPf.", null], - ["093730115115", "Breitenbrunn, M", null], - ["093730119119", "Deining", null], - ["093730121121", "Dietfurt a.d.Altmühl, St", null], - ["093730126126", "Freystadt, St", null], - ["093730134134", "Hohenfels, M", null], - ["093730140140", "Lauterhofen, M", null], - ["093730143143", "Lupburg, M", null], - ["093730146146", "Mühlhausen", null], - ["093730147147", "Neumarkt i.d.OPf., GKSt", null], - ["093730151151", "Parsberg, St", null], - ["093730155155", "Postbauer-Heng, M", null], - ["093730156156", "Pyrbaum, M", null], - ["093730160160", "Seubersdorf i.d.OPf.", null], - ["093730167167", "Velburg, St", null], - ["093735321114", "Berngau", null], - ["093735321153", "Pilsach", null], - ["093735321159", "Sengenthal", null], - ["093740111111", "Altenstadt a.d.Waldnaab", null], - ["093740118118", "Eslarn, M", null], - ["093740121121", "Floß, M", null], - ["093740122122", "Flossenbürg", null], - ["093740124124", "Grafenwöhr, St", null], - ["093740133133", "Luhe-Wildenau, M", null], - ["093740134134", "Mantel, M", null], - ["093740137137", "Moosbach, M", null], - ["093740139139", "Neustadt a.d.Waldnaab, St", null], - ["093740162162", "Vohenstrauß, St", null], - ["093740164164", "Waidhaus, M", null], - ["093740165165", "Waldthurn, M", null], - ["093740168168", "Windischeschenbach, St", null], - ["093745323128", "Kirchendemenreuth", null], - ["093745323144", "Parkstein, M", null], - ["093745323150", "Püchersreuth", null], - ["093745323158", "Störnstein", null], - ["093745323160", "Theisseil", null], - ["093745324148", "Trabitz", null], - ["093745324149", "Pressath, St", null], - ["093745324156", "Schwarzenbach", null], - ["093745325119", "Etzenricht", null], - ["093745325131", "Kohlberg, M", null], - ["093745325166", "Weiherhammer", null], - ["093745326129", "Kirchenthumbach, M", null], - ["093745326155", "Schlammersdorf", null], - ["093745326163", "Vorbach", null], - ["093745327117", "Eschenbach i.d.OPf., St", null], - ["093745327140", "Neustadt am Kulm, St", null], - ["093745327157", "Speinshart", null], - ["093745329127", "Irchenrieth", null], - ["093745329146", "Pirk", null], - ["093745329154", "Schirmitz", null], - ["093745329170", "Bechtsrieth", null], - ["093745330132", "Leuchtenberg, M", null], - ["093745330159", "Tännesberg, M", null], - ["093745331123", "Georgenberg", null], - ["093745331147", "Pleystein, St", null], - ["093749451451", "Heinersreuther Forst", null], - ["093749452452", "Manteler Forst", null], - ["093749458458", "Speinsharter Forst", null], - ["093750117117", "Barbing", null], - ["093750118118", "Beratzhausen, M", null], - ["093750119119", "Bernhardswald", null], - ["093750143143", "Hagelstadt", null], - ["093750148148", "Hemau, St", null], - ["093750161161", "Köfering", null], - ["093750165165", "Lappersdorf, M", null], - ["093750170170", "Mintraching", null], - ["093750174174", "Neutraubling, St", null], - ["093750175175", "Nittendorf, M", null], - ["093750179179", "Obertraubling", null], - ["093750180180", "Pentling", null], - ["093750181181", "Pettendorf", null], - ["093750183183", "Pfatter", null], - ["093750190190", "Regenstauf, M", null], - ["093750196196", "Schierling, M", null], - ["093750199199", "Sinzing", null], - ["093750204204", "Tegernheim", null], - ["093750205205", "Thalmassing", null], - ["093750208208", "Wenzenbach", null], - ["093750209209", "Wiesent", null], - ["093750213213", "Zeitlarn", null], - ["093755332131", "Duggendorf", null], - ["093755332153", "Holzheim a.Forst", null], - ["093755332156", "Kallmünz, M", null], - ["093755333122", "Brunn", null], - ["093755333127", "Deuerling", null], - ["093755333162", "Laaber, M", null], - ["093755334184", "Pielenhofen", null], - ["093755334211", "Wolfsegg", null], - ["093755335114", "Altenthann", null], - ["093755335116", "Bach a.d.Donau", null], - ["093755335130", "Donaustauf, M", null], - ["093755336120", "Brennberg", null], - ["093755336210", "Wörth a.d.Donau, St", null], - ["093755337113", "Alteglofsheim", null], - ["093755337182", "Pfakofen", null], - ["093755338115", "Aufhausen", null], - ["093755338171", "Mötzing", null], - ["093755338191", "Riekofen", null], - ["093755338201", "Sünching", null], - ["093759451451", "Forstmühler Forst", null], - ["093759452452", "Kreuther Forst", null], - ["093760116116", "Bodenwöhr", null], - ["093760117117", "Bruck i.d.OPf., M", null], - ["093760119119", "Burglengenfeld, St", null], - ["093760125125", "Fensterbach", null], - ["093760141141", "Maxhütte-Haidhof, St", null], - ["093760147147", "Neunburg vorm Wald, St", null], - ["093760149149", "Nittenau, St", null], - ["093760150150", "Wernberg-Köblitz, M", null], - ["093760151151", "Oberviechtach, St", null], - ["093760159159", "Schmidgaden", null], - ["093760161161", "Schwandorf, GKSt", null], - ["093760170170", "Teublitz, St", null], - ["093765339131", "Gleiritsch", null], - ["093765339148", "Niedermurach", null], - ["093765339171", "Teunz", null], - ["093765339178", "Winklarn, M", null], - ["093765341112", "Altendorf", null], - ["093765341133", "Guteneck", null], - ["093765341144", "Nabburg, St", null], - ["093765342162", "Schwarzach b.Nabburg", null], - ["093765342163", "Schwarzenfeld, M", null], - ["093765342169", "Stulln", null], - ["093765343153", "Pfreimd, St", null], - ["093765343173", "Trausnitz", null], - ["093765344160", "Schönsee, St", null], - ["093765344167", "Stadlern", null], - ["093765344176", "Weiding", null], - ["093765345122", "Dieterskirchen", null], - ["093765345146", "Neukirchen-Balbini, M", null], - ["093765345164", "Schwarzhofen, M", null], - ["093765345172", "Thanstein", null], - ["093765346168", "Steinberg am See", null], - ["093765346175", "Wackersdorf", null], - ["093769455455", "Wolferlohe", null], - ["093770112112", "Bärnau, St", null], - ["093770116116", "Erbendorf, St", null], - ["093770118118", "Friedenfels", null], - ["093770119119", "Fuchsmühl, M", null], - ["093770127127", "Immenreuth", null], - ["093770131131", "Konnersreuth, M", null], - ["093770133133", "Kulmain", null], - ["093770139139", "Mähring, M", null], - ["093770142142", "Bad Neualbenreuth, M", null], - ["093770146146", "Plößberg, M", null], - ["093770154154", "Tirschenreuth, St", null], - ["093770157157", "Waldershof, St", null], - ["093770158158", "Waldsassen, St", null], - ["093775347137", "Leonberg", null], - ["093775347141", "Mitterteich, St", null], - ["093775347145", "Pechbrunn", null], - ["093775348128", "Kastl", null], - ["093775348129", "Kemnath, St", null], - ["093775349113", "Brand", null], - ["093775349115", "Ebnath", null], - ["093775349143", "Neusorg", null], - ["093775349148", "Pullenreuth", null], - ["093775350132", "Krummennaab", null], - ["093775350149", "Reuth b.Erbendorf", null], - ["093775351117", "Falkenberg, M", null], - ["093775351159", "Wiesau, M", null], - ["094610000000", "Bamberg", null], - ["094620000000", "Bayreuth", null], - ["094630000000", "Coburg", null], - ["094640000000", "Hof", null], - ["094710111111", "Altendorf", null], - ["094710117117", "Bischberg", null], - ["094710119119", "Breitengüßbach", null], - ["094710123123", "Buttenheim, M", null], - ["094710131131", "Frensdorf", null], - ["094710137137", "Gundelsheim", null], - ["094710140140", "Hallstadt, St", null], - ["094710142142", "Heiligenstadt i.OFr., M", null], - ["094710145145", "Hirschaid, M", null], - ["094710150150", "Kemmern", null], - ["094710155155", "Litzendorf", null], - ["094710159159", "Memmelsdorf", null], - ["094710165165", "Oberhaid", null], - ["094710169169", "Pettstadt", null], - ["094710172172", "Pommersfelden", null], - ["094710174174", "Rattelsdorf, M", null], - ["094710185185", "Scheßlitz, St", null], - ["094710191191", "Stegaurach", null], - ["094710195195", "Strullendorf", null], - ["094710207207", "Viereth-Trunstadt", null], - ["094710208208", "Walsdorf", null], - ["094710214214", "Zapfendorf, M", null], - ["094710220220", "Schlüsselfeld, St", null], - ["094715401115", "Baunach, St", null], - ["094715401133", "Gerach", null], - ["094715401152", "Lauter", null], - ["094715401175", "Reckendorf", null], - ["094715403151", "Königsfeld", null], - ["094715403189", "Stadelhofen", null], - ["094715403209", "Wattendorf", null], - ["094715407122", "Burgwindheim, M", null], - ["094715407128", "Ebrach, M", null], - ["094715408120", "Burgebrach, M", null], - ["094715408186", "Schönbrunn i.Steigerwald", null], - ["094715445154", "Lisberg", null], - ["094715445173", "Priesendorf", null], - ["094719452452", "Ebracher Forst", null], - ["094719453453", "Eichwald", null], - ["094719454454", "Geisberger Forst", null], - ["094719455455", "Hauptsmoor", null], - ["094719456456", "Koppenwinder Forst", null], - ["094719457457", "Lindach", null], - ["094719459459", "Semberg", null], - ["094719460460", "Steinachsrangen", null], - ["094719461461", "Winkelhofer Forst", null], - ["094719462462", "Zückshuter Forst", null], - ["094720111111", "Ahorntal", null], - ["094720116116", "Bad Berneck i.Fichtelgebirge, St", null], - ["094720119119", "Bindlach", null], - ["094720121121", "Bischofsgrün", null], - ["094720131131", "Eckersdorf", null], - ["094720138138", "Fichtelberg", null], - ["094720139139", "Gefrees, St", null], - ["094720143143", "Goldkronach, St", null], - ["094720150150", "Heinersreuth", null], - ["094720164164", "Mehlmeisel", null], - ["094720175175", "Pegnitz, St", null], - ["094720179179", "Pottenstein, St", null], - ["094720190190", "Speichersdorf", null], - ["094720197197", "Waischenfeld, St", null], - ["094720198198", "Warmensteinach", null], - ["094725412115", "Aufseß", null], - ["094725412154", "Hollfeld, St", null], - ["094725412176", "Plankenfels", null], - ["094725413141", "Glashütten", null], - ["094725413167", "Mistelgau", null], - ["094725414140", "Gesees", null], - ["094725414155", "Hummeltal", null], - ["094725414166", "Mistelbach", null], - ["094725415133", "Emtmannsberg", null], - ["094725415156", "Kirchenpingarten", null], - ["094725415188", "Seybothenreuth", null], - ["094725415199", "Weidenberg, M", null], - ["094725416127", "Creußen, St", null], - ["094725416146", "Haag", null], - ["094725416180", "Prebitz", null], - ["094725416184", "Schnabelwaid, M", null], - ["094725417118", "Betzenstein, St", null], - ["094725417177", "Plech, M", null], - ["094729451451", "Bischofsgrüner Forst", null], - ["094729453453", "Fichtelberg", null], - ["094729454454", "Forst Neustädtlein a.Forst", null], - ["094729456456", "Glashüttener Forst", null], - ["094729458458", "Heinersreuther Forst", null], - ["094729463463", "Neubauer Forst-Nord", null], - ["094729464464", "Prüll", null], - ["094729468468", "Veldensteinerforst", null], - ["094729469469", "Waidacher Forst", null], - ["094729470470", "Warmensteinacher Forst-Nord", null], - ["094730112112", "Ahorn", null], - ["094730120120", "Dörfles-Esbach", null], - ["094730121121", "Ebersdorf b.Coburg", null], - ["094730132132", "Großheirath", null], - ["094730138138", "Itzgrund", null], - ["094730141141", "Lautertal", null], - ["094730144144", "Meeder", null], - ["094730151151", "Neustadt b.Coburg, GKSt", null], - ["094730158158", "Bad Rodach, St", null], - ["094730159159", "Rödental, St", null], - ["094730165165", "Seßlach, St", null], - ["094730166166", "Sonnefeld", null], - ["094730170170", "Untersiemau", null], - ["094730174174", "Weidhausen b.Coburg", null], - ["094730175175", "Weitramsdorf", null], - ["094735418134", "Grub a.Forst", null], - ["094735418153", "Niederfüllbach", null], - ["094739452452", "Callenberger Forst-West", null], - ["094739453453", "Gellnhausen", null], - ["094739454454", "Köllnholz", null], - ["094740123123", "Eggolsheim, M", null], - ["094740124124", "Egloffstein, M", null], - ["094740126126", "Forchheim, GKSt", null], - ["094740129129", "Gößweinstein, M", null], - ["094740133133", "Hallerndorf", null], - ["094740134134", "Hausen", null], - ["094740135135", "Heroldsbach", null], - ["094740140140", "Igensdorf, M", null], - ["094740146146", "Langensendelbach", null], - ["094740154154", "Neunkirchen a.Brand, M", null], - ["094740156156", "Obertrubach", null], - ["094740161161", "Pretzfeld, M", null], - ["094740176176", "Wiesenttal, M", null], - ["094745420121", "Ebermannstadt, St", null], - ["094745420168", "Unterleinleiter", null], - ["094745422145", "Kunreuth", null], - ["094745422158", "Pinzberg", null], - ["094745422175", "Wiesenthau", null], - ["094745423143", "Kirchehrenbach", null], - ["094745423147", "Leutenbach", null], - ["094745423171", "Weilersbach", null], - ["094745425122", "Effeltrich", null], - ["094745425160", "Poxdorf", null], - ["094745426119", "Dormitz", null], - ["094745426137", "Hetzles", null], - ["094745426144", "Kleinsendelbach", null], - ["094745427132", "Gräfenberg, St", null], - ["094745427138", "Hiltpoltstein, M", null], - ["094745427173", "Weißenohe", null], - ["094750112112", "Bad Steben, M", null], - ["094750113113", "Berg", null], - ["094750120120", "Döhlau", null], - ["094750128128", "Geroldsgrün", null], - ["094750136136", "Helmbrechts, St", null], - ["094750141141", "Köditz", null], - ["094750142142", "Konradsreuth", null], - ["094750154154", "Münchberg, St", null], - ["094750156156", "Naila, St", null], - ["094750158158", "Oberkotzau, M", null], - ["094750161161", "Regnitzlosau", null], - ["094750162162", "Rehau, St", null], - ["094750168168", "Schwarzenbach a.d.Saale, St", null], - ["094750169169", "Schwarzenbach a.Wald, St", null], - ["094750171171", "Selbitz, St", null], - ["094750175175", "Stammbach, M", null], - ["094750189189", "Zell im Fichtelgebirge, M", null], - ["094755428137", "Issigau", null], - ["094755428146", "Lichtenberg, St", null], - ["094755430123", "Feilitzsch", null], - ["094755430127", "Gattendorf", null], - ["094755430181", "Töpen", null], - ["094755430182", "Trogen", null], - ["094755431145", "Leupoldsgrün", null], - ["094755431165", "Schauenstein, St", null], - ["094755432174", "Sparneck, M", null], - ["094755432184", "Weißdorf", null], - ["094759451451", "Forst Schwarzenbach a.Wald", null], - ["094759452452", "Gerlaser Forst", null], - ["094759453453", "Geroldsgrüner Forst", null], - ["094759454454", "Martinlamitzer Forst-Nord", null], - ["094760145145", "Kronach, St", null], - ["094760146146", "Küps, M", null], - ["094760152152", "Ludwigsstadt, St", null], - ["094760159159", "Nordhalben, M", null], - ["094760164164", "Pressig, M", null], - ["094760175175", "Steinbach a.Wald", null], - ["094760177177", "Steinwiesen, M", null], - ["094760178178", "Stockheim", null], - ["094760179179", "Tettau, M", null], - ["094760183183", "Marktrodach, M", null], - ["094760184184", "Wallenfels, St", null], - ["094760185185", "Weißenbrunn", null], - ["094760189189", "Wilhelmsthal", null], - ["094765433166", "Reichenbach", null], - ["094765433180", "Teuschnitz, St", null], - ["094765433182", "Tschirn", null], - ["094765434154", "Mitwitz, M", null], - ["094765434171", "Schneckenlohe", null], - ["094769451451", "Birnbaum", null], - ["094769453453", "Langenbacher Forst", null], - ["094770121121", "Himmelkron", null], - ["094770128128", "Kulmbach, GKSt", null], - ["094770136136", "Mainleus, M", null], - ["094770139139", "Marktschorgast, M", null], - ["094770142142", "Neudrossenfeld", null], - ["094770143143", "Neuenmarkt", null], - ["094770148148", "Presseck, M", null], - ["094770157157", "Thurnau, M", null], - ["094770163163", "Wirsberg, M", null], - ["094775435151", "Rugendorf", null], - ["094775435156", "Stadtsteinach, St", null], - ["094775436117", "Grafengehaig, M", null], - ["094775436138", "Marktleugast, M", null], - ["094775437118", "Guttenberg", null], - ["094775437129", "Kupferberg, St", null], - ["094775437135", "Ludwigschorgast, M", null], - ["094775437159", "Untersteinach", null], - ["094775438124", "Kasendorf, M", null], - ["094775438164", "Wonsees, M", null], - ["094775439119", "Harsdorf", null], - ["094775439127", "Ködnitz", null], - ["094775439158", "Trebgast", null], - ["094780111111", "Altenkunstadt", null], - ["094780116116", "Burgkunstadt, St", null], - ["094780120120", "Ebensfeld, M", null], - ["094780139139", "Lichtenfels, St", null], - ["094780145145", "Michelau i.OFr.", null], - ["094780165165", "Bad Staffelstein, St", null], - ["094780176176", "Weismain, St", null], - ["094785441143", "Marktgraitz, M", null], - ["094785441155", "Redwitz a.d.Rodach", null], - ["094785446127", "Hochstadt a.Main", null], - ["094785446144", "Marktzeuln, M", null], - ["094789451451", "Breitengüßbacher Forst", null], - ["094789453453", "Neuensorger Forst", null], - ["094790112112", "Arzberg, St", null], - ["094790129129", "Kirchenlamitz, St", null], - ["094790135135", "Marktleuthen, St", null], - ["094790136136", "Marktredwitz, GKSt", null], - ["094790145145", "Röslau", null], - ["094790150150", "Schönwald, St", null], - ["094790152152", "Selb, GKSt", null], - ["094790166166", "Weißenstadt, St", null], - ["094790169169", "Wunsiedel, St", null], - ["094795442126", "Höchstädt i.Fichtelgebirge", null], - ["094795442158", "Thiersheim, M", null], - ["094795442159", "Thierstein, M", null], - ["094795443127", "Hohenberg a.d.Eger, St", null], - ["094795443147", "Schirnding, M", null], - ["094795444111", "Bad Alexandersbad", null], - ["094795444138", "Nagel", null], - ["094795444161", "Tröstau", null], - ["094799453453", "Kaiserhammer Forst-Ost", null], - ["094799455455", "Martinlamitzer Forst-Süd", null], - ["094799456456", "Meierhöfer Seite", null], - ["094799457457", "Neubauer Forst-Süd", null], - ["094799459459", "Tröstauer Forst-Ost", null], - ["094799460460", "Tröstauer Forst-West", null], - ["094799461461", "Vordorfer Forst", null], - ["094799462462", "Weißenstadter Forst-Nord", null], - ["094799463463", "Weißenstadter Forst-Süd", null], - ["095610000000", "Ansbach", null], - ["095620000000", "Erlangen", null], - ["095630000000", "Fürth", null], - ["095640000000", "Nürnberg", null], - ["095650000000", "Schwabach", null], - ["095710113113", "Arberg, M", null], - ["095710114114", "Aurach", null], - ["095710115115", "Bechhofen, M", null], - ["095710127127", "Burgoberbach", null], - ["095710130130", "Colmberg, M", null], - ["095710135135", "Dietenhofen, M", null], - ["095710136136", "Dinkelsbühl, GKSt", null], - ["095710139139", "Dürrwangen, M", null], - ["095710145145", "Feuchtwangen, St", null], - ["095710146146", "Flachslanden, M", null], - ["095710165165", "Heilsbronn, St", null], - ["095710166166", "Herrieden, St", null], - ["095710170170", "Langfurth", null], - ["095710171171", "Lehrberg, M", null], - ["095710174174", "Leutershausen, St", null], - ["095710175175", "Lichtenau, M", null], - ["095710177177", "Merkendorf, St", null], - ["095710180180", "Neuendettelsau", null], - ["095710183183", "Oberdachstetten", null], - ["095710190190", "Petersaurach", null], - ["095710193193", "Rothenburg ob der Tauber, GKSt", null], - ["095710196196", "Sachsen b.Ansbach", null], - ["095710199199", "Schnelldorf", null], - ["095710200200", "Schopfloch, M", null], - ["095710214214", "Wassertrüdingen, St", null], - ["095710226226", "Windsbach, St", null], - ["095715501111", "Adelshofen", null], - ["095715501152", "Gebsattel", null], - ["095715501155", "Geslau", null], - ["095715501169", "Insingen", null], - ["095715501181", "Neusitz", null], - ["095715501188", "Ohrenbach", null], - ["095715501205", "Steinsfeld", null], - ["095715501225", "Windelsbach", null], - ["095715502125", "Buch a.Wald", null], - ["095715502134", "Diebach", null], - ["095715502137", "Dombühl, M", null], - ["095715502198", "Schillingsfürst, St", null], - ["095715502222", "Wettringen", null], - ["095715502228", "Wörnitz", null], - ["095715504122", "Bruckberg", null], - ["095715504194", "Rügland", null], - ["095715504217", "Weihenzell", null], - ["095715506189", "Ornbau, St", null], - ["095715506216", "Weidenbach, M", null], - ["095715507128", "Burk", null], - ["095715507132", "Dentlein a.Forst, M", null], - ["095715507223", "Wieseth", null], - ["095715508179", "Mönchsroth", null], - ["095715508218", "Weiltingen, M", null], - ["095715508224", "Wilburgstetten", null], - ["095715509141", "Ehingen", null], - ["095715509154", "Gerolfingen", null], - ["095715509192", "Röckingen", null], - ["095715509208", "Unterschwaningen", null], - ["095715509227", "Wittelshofen", null], - ["095715538178", "Mitteleschenbach", null], - ["095715538229", "Wolframs-Eschenbach, St", null], - ["095719451451", "Unterer Wald", null], - ["095720111111", "Adelsdorf", null], - ["095720115115", "Baiersdorf, St", null], - ["095720119119", "Bubenreuth", null], - ["095720121121", "Eckental, M", null], - ["095720130130", "Hemhofen", null], - ["095720131131", "Heroldsberg, M", null], - ["095720132132", "Herzogenaurach, St", null], - ["095720135135", "Höchstadt a.d.Aisch, St", null], - ["095720137137", "Kalchreuth", null], - ["095720142142", "Möhrendorf", null], - ["095720149149", "Röttenbach", null], - ["095720160160", "Wachenroth, M", null], - ["095720164164", "Weisendorf, M", null], - ["095725510126", "Gremsdorf", null], - ["095725510139", "Lonnerstadt, M", null], - ["095725510143", "Mühlhausen, M", null], - ["095725510159", "Vestenbergsgreuth, M", null], - ["095725512114", "Aurachtal", null], - ["095725512147", "Oberreichenbach", null], - ["095725514120", "Buckenhof", null], - ["095725514141", "Marloffstein", null], - ["095725514154", "Spardorf", null], - ["095725514158", "Uttenreuth", null], - ["095725539127", "Großenseebach", null], - ["095725539133", "Heßdorf", null], - ["095729451451", "Birkach", null], - ["095729452452", "Buckenhofer Forst", null], - ["095729453453", "Dormitzer Forst", null], - ["095729454454", "Erlenstegener Forst", null], - ["095729455455", "Forst Tennenlohe", null], - ["095729456456", "Geschaidt", null], - ["095729457457", "Kalchreuther Forst", null], - ["095729458458", "Kraftshofer Forst", null], - ["095729459459", "Mark", null], - ["095729460460", "Neunhofer Forst", null], - ["095730111111", "Ammerndorf, M", null], - ["095730114114", "Cadolzburg, M", null], - ["095730115115", "Großhabersdorf", null], - ["095730120120", "Langenzenn, St", null], - ["095730122122", "Oberasbach, St", null], - ["095730124124", "Puschendorf", null], - ["095730125125", "Roßtal, M", null], - ["095730127127", "Stein, St", null], - ["095730133133", "Wilhermsdorf, M", null], - ["095730134134", "Zirndorf, St", null], - ["095735517126", "Seukendorf", null], - ["095735517130", "Veitsbronn", null], - ["095735540123", "Obermichelbach", null], - ["095735540129", "Tuchenbach", null], - ["095740112112", "Altdorf b.Nürnberg, St", null], - ["095740117117", "Burgthann", null], - ["095740123123", "Feucht, M", null], - ["095740132132", "Hersbruck, St", null], - ["095740135135", "Kirchensittenbach", null], - ["095740138138", "Lauf a.d.Pegnitz, St", null], - ["095740139139", "Leinburg", null], - ["095740140140", "Neuhaus a.d.Pegnitz, M", null], - ["095740141141", "Neunkirchen a.Sand", null], - ["095740146146", "Ottensoos", null], - ["095740147147", "Pommelsbrunn", null], - ["095740150150", "Reichenschwand", null], - ["095740152152", "Röthenbach a.d.Pegnitz, St", null], - ["095740154154", "Rückersdorf", null], - ["095740155155", "Schnaittach, M", null], - ["095740156156", "Schwaig b.Nürnberg", null], - ["095740157157", "Schwarzenbruck", null], - ["095740158158", "Simmelsdorf", null], - ["095740164164", "Winkelhaid", null], - ["095745527129", "Hartenstein", null], - ["095745527160", "Velden, St", null], - ["095745527161", "Vorra", null], - ["095745528111", "Alfeld", null], - ["095745528128", "Happurg", null], - ["095745529120", "Engelthal", null], - ["095745529131", "Henfenfeld", null], - ["095745529145", "Offenhausen", null], - ["095749451451", "Behringersdorfer Forst", null], - ["095749452452", "Brunn", null], - ["095749453453", "Engelthaler Forst", null], - ["095749454454", "Feuchter Forst", null], - ["095749455455", "Fischbach", null], - ["095749456456", "Forsthof", null], - ["095749457457", "Günthersbühler Forst", null], - ["095749458458", "Haimendorfer Forst", null], - ["095749460460", "Laufamholzer Forst", null], - ["095749461461", "Leinburg", null], - ["095749462462", "Rückersdorfer Forst", null], - ["095749463463", "Schönberg", null], - ["095749464464", "Winkelhaid", null], - ["095749465465", "Zerzabelshofer Forst", null], - ["095750112112", "Bad Windsheim, St", null], - ["095750116116", "Burghaslach, M", null], - ["095750119119", "Dietersheim", null], - ["095750121121", "Emskirchen, M", null], - ["095750135135", "Ipsheim, M", null], - ["095750145145", "Markt Erlbach, M", null], - ["095750153153", "Neustadt a.d.Aisch, St", null], - ["095750156156", "Obernzenn, M", null], - ["095755518138", "Langenfeld", null], - ["095755518144", "Markt Bibart, M", null], - ["095755518147", "Markt Taschendorf, M", null], - ["095755518157", "Oberscheinfeld, M", null], - ["095755518161", "Scheinfeld, St", null], - ["095755518165", "Sugenheim, M", null], - ["095755519122", "Ergersheim", null], - ["095755519127", "Gollhofen", null], - ["095755519130", "Hemmersheim", null], - ["095755519134", "Ippesheim, M", null], - ["095755519146", "Markt Nordheim, M", null], - ["095755519155", "Oberickelsheim", null], - ["095755519163", "Simmershofen", null], - ["095755519168", "Uffenheim, St", null], - ["095755519179", "Weigenheim", null], - ["095755520129", "Hagenbüchach", null], - ["095755520181", "Wilhelmsdorf", null], - ["095755521113", "Baudenbach, M", null], - ["095755521118", "Diespeck", null], - ["095755521128", "Gutenstetten", null], - ["095755521150", "Münchsteinach", null], - ["095755522117", "Dachsbach, M", null], - ["095755522125", "Gerhardshofen", null], - ["095755522167", "Uehlfeld, M", null], - ["095755524115", "Burgbernheim, St", null], - ["095755524124", "Gallmersgarten", null], - ["095755524133", "Illesheim", null], - ["095755524143", "Marktbergel, M", null], - ["095755525152", "Neuhof a.d.Zenn, M", null], - ["095755525166", "Trautskirchen", null], - ["095759451451", "Osing", null], - ["095760111111", "Abenberg, St", null], - ["095760113113", "Allersberg, M", null], - ["095760117117", "Büchenbach", null], - ["095760121121", "Georgensgmünd", null], - ["095760122122", "Greding, St", null], - ["095760126126", "Heideck, St", null], - ["095760127127", "Hilpoltstein, St", null], - ["095760128128", "Kammerstein", null], - ["095760132132", "Schwanstetten, M", null], - ["095760137137", "Rednitzhembach", null], - ["095760141141", "Röttenbach", null], - ["095760142142", "Rohr", null], - ["095760143143", "Roth, St", null], - ["095760147147", "Spalt, St", null], - ["095760148148", "Thalmässing, M", null], - ["095760151151", "Wendelstein, M", null], - ["095769451451", "Abenberger Wald", null], - ["095769452452", "Dechenwald", null], - ["095769453453", "Forst Kleinschwarzenlohe", null], - ["095769454454", "Heidenberg", null], - ["095769455455", "Soos", null], - ["095770114114", "Muhr a.See", null], - ["095770136136", "Gunzenhausen, St", null], - ["095770148148", "Langenaltheim", null], - ["095770158158", "Pappenheim, St", null], - ["095770161161", "Pleinfeld, M", null], - ["095770162162", "Polsingen", null], - ["095770168168", "Solnhofen", null], - ["095770173173", "Treuchtlingen, St", null], - ["095770177177", "Weißenburg i.Bay., GKSt", null], - ["095775532111", "Absberg, M", null], - ["095775532138", "Haundorf", null], - ["095775532159", "Pfofeld", null], - ["095775532172", "Theilenhofen", null], - ["095775533113", "Alesheim", null], - ["095775533122", "Dittenheim", null], - ["095775533149", "Markt Berolzheim, M", null], - ["095775533150", "Meinheim", null], - ["095775534125", "Ellingen, St", null], - ["095775534127", "Ettenstatt", null], - ["095775534141", "Höttingen", null], - ["095775535115", "Bergen", null], - ["095775535120", "Burgsalach", null], - ["095775535151", "Nennslingen, M", null], - ["095775535163", "Raitenbuch", null], - ["095775536133", "Gnotzheim, M", null], - ["095775536140", "Heidenheim, M", null], - ["095775536179", "Westheim", null], - ["096610000000", "Aschaffenburg", null], - ["096620000000", "Schweinfurt", null], - ["096630000000", "Würzburg", null], - ["096710111111", "Alzenau, St", null], - ["096710112112", "Bessenbach", null], - ["096710114114", "Karlstein a.Main", null], - ["096710119119", "Geiselbach", null], - ["096710120120", "Glattbach", null], - ["096710121121", "Goldbach, M", null], - ["096710122122", "Großostheim, M", null], - ["096710124124", "Haibach", null], - ["096710130130", "Hösbach, M", null], - ["096710133133", "Johannesberg", null], - ["096710134134", "Kahl a.Main", null], - ["096710136136", "Kleinostheim", null], - ["096710139139", "Laufach", null], - ["096710140140", "Mainaschaff", null], - ["096710143143", "Mömbris, M", null], - ["096710148148", "Rothenbuch", null], - ["096710150150", "Sailauf", null], - ["096710155155", "Stockstadt a.Main, M", null], - ["096710156156", "Waldaschaff", null], - ["096710157157", "Weibersbrunn", null], - ["096715602126", "Heigenbrücken", null], - ["096715602128", "Heinrichsthal", null], - ["096715603127", "Heimbuchenthal", null], - ["096715603141", "Mespelbrunn", null], - ["096715603160", "Dammbach", null], - ["096715604113", "Blankenbach", null], - ["096715604135", "Kleinkahl", null], - ["096715604138", "Krombach", null], - ["096715604152", "Schöllkrippen, M", null], - ["096715604153", "Sommerkahl", null], - ["096715604159", "Westerngrund", null], - ["096715604162", "Wiesen", null], - ["096719451451", "Forst Hain i.Spessart", null], - ["096719453453", "Heinrichsthaler Forst", null], - ["096719456456", "Rohrbrunner Forst", null], - ["096719457457", "Rothenbucher Forst", null], - ["096719458458", "Sailaufer Forst", null], - ["096719459459", "Schöllkrippener Forst", null], - ["096719460460", "Waldaschaffer Forst", null], - ["096719461461", "Wiesener Forst", null], - ["096720112112", "Bad Bocklet, M", null], - ["096720113113", "Bad Brückenau, St", null], - ["096720114114", "Bad Kissingen, GKSt", null], - ["096720117117", "Burkardroth, M", null], - ["096720127127", "Hammelburg, St", null], - ["096720134134", "Motten", null], - ["096720135135", "Münnerstadt, St", null], - ["096720136136", "Nüdlingen", null], - ["096720139139", "Oberthulba, M", null], - ["096720140140", "Oerlenbach", null], - ["096720161161", "Wartmannsroth", null], - ["096720163163", "Wildflecken, M", null], - ["096720166166", "Zeitlofs, M", null], - ["096725606126", "Geroda, M", null], - ["096725606138", "Oberleichtersbach", null], - ["096725606145", "Riedenberg", null], - ["096725606149", "Schondra, M", null], - ["096725607121", "Elfershausen, M", null], - ["096725607124", "Fuchsstadt", null], - ["096725608111", "Aura a.d.Saale", null], - ["096725608122", "Euerdorf, M", null], - ["096725608142", "Ramsthal", null], - ["096725608155", "Sulzthal, M", null], - ["096725609131", "Maßbach, M", null], - ["096725609143", "Rannungen", null], - ["096725609157", "Thundorf i.UFr.", null], - ["096729451451", "Dreistelzer Forst", null], - ["096729454454", "Forst Detter-Süd", null], - ["096729455455", "Geiersnest-Ost", null], - ["096729456456", "Geiersnest-West", null], - ["096729457457", "Großer Auersberg", null], - ["096729458458", "Kälberberg", null], - ["096729461461", "Mottener Forst-Süd", null], - ["096729462462", "Neuwirtshauser Forst", null], - ["096729463463", "Omerz u. Roter Berg", null], - ["096729464464", "Römershager Forst-Nord", null], - ["096729465465", "Römershager Forst-Ost", null], - ["096729466466", "Roßbacher Forst", null], - ["096729468468", "Waldfensterer Forst", null], - ["096730114114", "Bad Neustadt a.d.Saale, St", null], - ["096730116116", "Bastheim", null], - ["096730117117", "Bischofsheim i.d.Rhön, St", null], - ["096730141141", "Bad Königshofen i.Grabfeld, St", null], - ["096730149149", "Oberelsbach, M", null], - ["096730162162", "Sandberg", null], - ["096735633130", "Hendungen", null], - ["096735633142", "Mellrichstadt, St", null], - ["096735633151", "Oberstreu", null], - ["096735633170", "Stockheim", null], - ["096735634113", "Aubstadt", null], - ["096735634126", "Großbardorf", null], - ["096735634131", "Herbstadt", null], - ["096735634134", "Höchheim", null], - ["096735634172", "Sulzdorf a.d.Lederhecke", null], - ["096735634173", "Sulzfeld", null], - ["096735634174", "Trappstadt, M", null], - ["096735635135", "Hohenroth", null], - ["096735635146", "Niederlauer", null], - ["096735635156", "Rödelmaier", null], - ["096735635161", "Salz", null], - ["096735635163", "Schönau a.d.Brend", null], - ["096735635171", "Strahlungen", null], - ["096735635186", "Burglauer", null], - ["096735637123", "Fladungen, St", null], - ["096735637129", "Hausen", null], - ["096735637147", "Nordheim v.d.Rhön", null], - ["096735638133", "Heustreu", null], - ["096735638136", "Hollstadt", null], - ["096735638175", "Unsleben", null], - ["096735638183", "Wollbach", null], - ["096735639153", "Ostheim v.d.Rhön, St", null], - ["096735639167", "Sondheim v.d.Rhön", null], - ["096735639182", "Willmars", null], - ["096735640127", "Großeibstadt", null], - ["096735640160", "Saal a.d.Saale, M", null], - ["096735640184", "Wülfershausen a.d.Saale", null], - ["096739451451", "Bundorfer Forst", null], - ["096739452452", "Burgwallbacher Forst", null], - ["096739453453", "Forst Schmalwasser-Nord", null], - ["096739454454", "Forst Schmalwasser-Süd", null], - ["096739455455", "Mellrichstadter Forst", null], - ["096739456456", "Steinacher Forst r.d.Saale", null], - ["096739457457", "Sulzfelder Forst", null], - ["096739458458", "Weigler", null], - ["096740133133", "Eltmann, St", null], - ["096740147147", "Haßfurt, St", null], - ["096740159159", "Oberaurach", null], - ["096740163163", "Knetzgau", null], - ["096740164164", "Königsberg i.Bay., St", null], - ["096740171171", "Maroldsweisach, M", null], - ["096740187187", "Rauhenebrach", null], - ["096740195195", "Sand a.Main", null], - ["096740210210", "Untermerzbach", null], - ["096740221221", "Zeil a.Main, St", null], - ["096745610118", "Breitbrunn", null], - ["096745610129", "Ebelsbach", null], - ["096745610160", "Kirchlauter", null], - ["096745610201", "Stettfeld", null], - ["096745611130", "Ebern, St", null], - ["096745611184", "Pfarrweisach", null], - ["096745611190", "Rentweinsdorf, M", null], - ["096745612111", "Aidhausen", null], - ["096745612120", "Bundorf", null], - ["096745612121", "Burgpreppach, M", null], - ["096745612149", "Hofheim i.UFr., St", null], - ["096745612153", "Riedbach", null], - ["096745612223", "Ermershausen", null], - ["096745613139", "Gädheim", null], - ["096745613180", "Theres", null], - ["096745613219", "Wonfurt", null], - ["096750117117", "Dettelbach, St", null], - ["096750127127", "Geiselwind, M", null], - ["096750141141", "Kitzingen, GKSt", null], - ["096750144144", "Mainbernheim, St", null], - ["096750158158", "Prichsenstadt, St", null], - ["096750165165", "Schwarzach a.Main, M", null], - ["096755614111", "Abtswind, M", null], - ["096755614116", "Castell", null], - ["096755614162", "Rüdenhausen, M", null], - ["096755614178", "Wiesentheid, M", null], - ["096755615131", "Großlangheim, M", null], - ["096755615142", "Kleinlangheim, M", null], - ["096755615177", "Wiesenbronn", null], - ["096755616139", "Iphofen, St", null], - ["096755616148", "Markt Einersheim, M", null], - ["096755616161", "Rödelsee", null], - ["096755616179", "Willanzheim, M", null], - ["096755617112", "Albertshofen", null], - ["096755617113", "Biebelried", null], - ["096755617114", "Buchbrunn", null], - ["096755617146", "Mainstockheim", null], - ["096755617170", "Sulzfeld a.Main", null], - ["096755618147", "Marktbreit, St", null], - ["096755618149", "Marktsteft, St", null], - ["096755618150", "Martinsheim", null], - ["096755618156", "Obernbreit, M", null], - ["096755618166", "Segnitz", null], - ["096755618167", "Seinsheim, M", null], - ["096755619155", "Nordheim a.Main", null], - ["096755619169", "Sommerach", null], - ["096755619174", "Volkach, St", null], - ["096760112112", "Amorbach, St", null], - ["096760117117", "Collenberg", null], - ["096760118118", "Dorfprozelten", null], - ["096760119119", "Eichenbühl", null], - ["096760121121", "Elsenfeld, M", null], - ["096760122122", "Erlenbach a.Main, St", null], - ["096760123123", "Eschau, M", null], - ["096760124124", "Faulbach", null], - ["096760125125", "Großheubach, M", null], - ["096760126126", "Großwallstadt", null], - ["096760131131", "Kirchzell, M", null], - ["096760134134", "Klingenberg a.Main, St", null], - ["096760136136", "Leidersbach", null], - ["096760139139", "Miltenberg, St", null], - ["096760140140", "Mömlingen", null], - ["096760144144", "Niedernberg", null], - ["096760145145", "Obernburg a.Main, St", null], - ["096760156156", "Schneeberg, M", null], - ["096760160160", "Sulzbach a.Main, M", null], - ["096760165165", "Weilbach, M", null], - ["096760169169", "Wörth a.Main, St", null], - ["096765626116", "Bürgstadt, M", null], - ["096765626143", "Neunkirchen", null], - ["096765627132", "Kleinheubach, M", null], - ["096765627135", "Laudenbach", null], - ["096765627153", "Rüdenau", null], - ["096765630128", "Hausen", null], - ["096765630133", "Kleinwallstadt, M", null], - ["096765631141", "Mönchberg, M", null], - ["096765631151", "Röllbach", null], - ["096765632111", "Altenbuch", null], - ["096765632158", "Stadtprozelten, St", null], - ["096769452452", "Forstwald", null], - ["096769455455", "Hohe Wart", null], - ["096770114114", "Arnstein, St", null], - ["096770127127", "Eußenheim", null], - ["096770129129", "Frammersbach, M", null], - ["096770131131", "Gemünden a.Main, St", null], - ["096770148148", "Karlstadt, St", null], - ["096770154154", "Triefenstein, M", null], - ["096770155155", "Lohr a.Main, St", null], - ["096770157157", "Marktheidenfeld, St", null], - ["096770177177", "Rieneck, St", null], - ["096775620137", "Hasloch", null], - ["096775620151", "Kreuzwertheim, M", null], - ["096775620182", "Schollbrunn", null], - ["096775621119", "Birkenfeld", null], - ["096775621120", "Bischbrunn", null], - ["096775621125", "Erlenbach b.Marktheidenfeld", null], - ["096775621126", "Esselbach", null], - ["096775621135", "Hafenlohr", null], - ["096775621146", "Karbach, M", null], - ["096775621178", "Roden", null], - ["096775621181", "Rothenfels, St", null], - ["096775621193", "Urspringen", null], - ["096775622116", "Aura i.Sinngrund", null], - ["096775622122", "Burgsinn, M", null], - ["096775622128", "Fellen", null], - ["096775622159", "Mittelsinn", null], - ["096775622169", "Obersinn, M", null], - ["096775623132", "Gössenheim", null], - ["096775623133", "Gräfendorf", null], - ["096775623149", "Karsbach", null], - ["096775624164", "Neuendorf", null], - ["096775624166", "Neustadt a.Main", null], - ["096775624172", "Rechtenbach", null], - ["096775624186", "Steinfeld", null], - ["096775625142", "Himmelstadt", null], - ["096775625175", "Retzstadt", null], - ["096775625189", "Thüngen, M", null], - ["096775625203", "Zellingen, M", null], - ["096775656165", "Neuhütten", null], - ["096775656170", "Partenstein", null], - ["096775656200", "Wiesthal", null], - ["096779452452", "Burgjoß", null], - ["096779453453", "Forst Aura", null], - ["096779454454", "Forst Lohrerstraße", null], - ["096779455455", "Frammersbacher Forst", null], - ["096779456456", "Fürstl. Löwenstein'scher Park", null], - ["096779457457", "Haurain", null], - ["096779458458", "Herrnwald", null], - ["096779459459", "Langenprozeltener Forst", null], - ["096779461461", "Partensteiner Forst", null], - ["096779463463", "Ruppertshüttener Forst", null], - ["096780115115", "Bergrheinfeld", null], - ["096780123123", "Dittelbrunn", null], - ["096780128128", "Euerbach", null], - ["096780132132", "Geldersheim", null], - ["096780135135", "Gochsheim", null], - ["096780136136", "Grafenrheinfeld", null], - ["096780138138", "Grettstadt", null], - ["096780150150", "Kolitzheim", null], - ["096780160160", "Niederwerrn", null], - ["096780168168", "Poppenhausen", null], - ["096780170170", "Röthlein", null], - ["096780174174", "Schonungen", null], - ["096780176176", "Schwebheim", null], - ["096780178178", "Sennfeld", null], - ["096780181181", "Stadtlauringen, M", null], - ["096780186186", "Üchtelhausen", null], - ["096780190190", "Waigolshausen", null], - ["096780192192", "Wasserlosen", null], - ["096780193193", "Werneck, M", null], - ["096785642122", "Dingolshausen", null], - ["096785642124", "Donnersdorf", null], - ["096785642130", "Frankenwinheim", null], - ["096785642134", "Gerolzhofen, St", null], - ["096785642153", "Lülsfeld", null], - ["096785642157", "Michelau i.Steigerwald", null], - ["096785642164", "Oberschwarzach, M", null], - ["096785642183", "Sulzheim", null], - ["096785643175", "Schwanfeld", null], - ["096785643196", "Wipfeld", null], - ["096789451451", "Bürgerwald", null], - ["096789452452", "Geiersberg", null], - ["096789453453", "Hundelshausen", null], - ["096789454454", "Nonnenkloster", null], - ["096789455455", "Stollbergerforst", null], - ["096789456456", "Vollburg", null], - ["096789457457", "Wustvieler Forst", null], - ["096790126126", "Eisingen", null], - ["096790134134", "Gaukönigshofen", null], - ["096790136136", "Gerbrunn", null], - ["096790142142", "Güntersleben", null], - ["096790143143", "Hausen b.Würzburg", null], - ["096790147147", "Höchberg, M", null], - ["096790155155", "Kleinrinderfeld", null], - ["096790156156", "Kürnach", null], - ["096790164164", "Neubrunn, M", null], - ["096790170170", "Ochsenfurt, St", null], - ["096790175175", "Randersacker, M", null], - ["096790176176", "Reichenberg, M", null], - ["096790180180", "Rimpar, M", null], - ["096790185185", "Rottendorf", null], - ["096790193193", "Theilheim", null], - ["096790194194", "Thüngersheim", null], - ["096790200200", "Leinach", null], - ["096790201201", "Unterpleichfeld", null], - ["096790202202", "Veitshöchheim", null], - ["096790204204", "Waldbrunn", null], - ["096790205205", "Waldbüttelbrunn", null], - ["096790209209", "Zell a.Main, M", null], - ["096795644114", "Aub, St", null], - ["096795644135", "Gelchsheim, M", null], - ["096795644188", "Sonderhofen", null], - ["096795645117", "Bergtheim", null], - ["096795645169", "Oberpleichfeld", null], - ["096795646124", "Eibelstadt, St", null], - ["096795646131", "Frickenhausen a.Main, M", null], - ["096795646187", "Sommerhausen, M", null], - ["096795646206", "Winterhausen, M", null], - ["096795647130", "Estenfeld", null], - ["096795647167", "Eisenheim, M", null], - ["096795647174", "Prosselsheim", null], - ["096795648122", "Bütthard, M", null], - ["096795648138", "Giebelstadt, M", null], - ["096795649144", "Helmstadt, M", null], - ["096795649149", "Holzkirchen", null], - ["096795649177", "Remlingen, M", null], - ["096795649196", "Uettingen", null], - ["096795650137", "Geroldshausen", null], - ["096795650153", "Kirchheim", null], - ["096795651154", "Kist", null], - ["096795651165", "Altertheim", null], - ["096795652128", "Erlabrunn", null], - ["096795652161", "Margetshöchheim", null], - ["096795654118", "Bieberehren", null], - ["096795654179", "Riedenheim", null], - ["096795654182", "Röttingen, St", null], - ["096795654192", "Tauberrettersheim", null], - ["096795655141", "Greußenheim", null], - ["096795655146", "Hettstadt", null], - ["096799451451", "Gramschatzer Wald", null], - ["096799452452", "Guttenberger Wald", null], - ["096799453453", "Irtenberger Wald", null], - ["097610000000", "Augsburg", null], - ["097620000000", "Kaufbeuren", null], - ["097630000000", "Kempten (Allgäu)", null], - ["097640000000", "Memmingen", null], - ["097710112112", "Affing", null], - ["097710113113", "Aichach, St", null], - ["097710130130", "Friedberg, St", null], - ["097710140140", "Hollenbach", null], - ["097710141141", "Inchenhofen, M", null], - ["097710142142", "Kissing", null], - ["097710145145", "Merching", null], - ["097710158158", "Rehling", null], - ["097710160160", "Ried", null], - ["097715701114", "Aindling, M", null], - ["097715701155", "Petersdorf", null], - ["097715701169", "Todtenweis", null], - ["097715703144", "Kühbach, M", null], - ["097715703162", "Schiltberg", null], - ["097715704111", "Adelzhausen", null], - ["097715704122", "Dasing", null], - ["097715704129", "Eurasburg", null], - ["097715704149", "Obergriesbach", null], - ["097715704165", "Sielenbach", null], - ["097715705146", "Mering, M", null], - ["097715705163", "Schmiechen", null], - ["097715705168", "Steindorf", null], - ["097715771156", "Pöttmes, M", null], - ["097715771176", "Baar (Schwaben)", null], - ["097720111111", "Adelsried", null], - ["097720115115", "Altenmünster", null], - ["097720117117", "Aystetten", null], - ["097720121121", "Biberbach, M", null], - ["097720125125", "Bobingen, St", null], - ["097720130130", "Diedorf, M", null], - ["097720131131", "Dinkelscherben, M", null], - ["097720141141", "Fischach, M", null], - ["097720145145", "Gablingen", null], - ["097720147147", "Gersthofen, St", null], - ["097720149149", "Graben", null], - ["097720159159", "Horgau", null], - ["097720163163", "Königsbrunn, St", null], - ["097720167167", "Kutzenhausen", null], - ["097720171171", "Langweid a.Lech", null], - ["097720177177", "Meitingen, M", null], - ["097720184184", "Neusäß, St", null], - ["097720200200", "Schwabmünchen, St", null], - ["097720202202", "Stadtbergen, St", null], - ["097720207207", "Thierhaupten, M", null], - ["097720215215", "Wehringen", null], - ["097720223223", "Zusmarshausen, M", null], - ["097725706114", "Allmannshofen", null], - ["097725706134", "Ehingen", null], - ["097725706136", "Ellgau", null], - ["097725706166", "Kühlenthal", null], - ["097725706185", "Nordendorf", null], - ["097725706217", "Westendorf", null], - ["097725707126", "Bonstetten", null], - ["097725707137", "Emersacker", null], - ["097725707156", "Heretsried", null], - ["097725707216", "Welden, M", null], - ["097725708148", "Gessertshausen", null], - ["097725708211", "Ustersbach", null], - ["097725709168", "Langenneufnach", null], - ["097725709178", "Mickhausen", null], - ["097725709179", "Mittelneufnach", null], - ["097725709197", "Scherstetten", null], - ["097725709214", "Walkertshofen", null], - ["097725710151", "Großaitingen", null], - ["097725710160", "Kleinaitingen", null], - ["097725710186", "Oberottmarshausen", null], - ["097725711162", "Klosterlechfeld", null], - ["097725711209", "Untermeitingen", null], - ["097725712157", "Hiltenfingen", null], - ["097725712170", "Langerringen", null], - ["097729451451", "Schmellerforst", null], - ["097730117117", "Bissingen, M", null], - ["097730122122", "Buttenwiesen", null], - ["097730125125", "Dillingen a.d.Donau, GKSt", null], - ["097730144144", "Lauingen (Donau), St", null], - ["097735713113", "Bächingen a.d.Brenz", null], - ["097735713136", "Gundelfingen a.d.Donau, St", null], - ["097735713137", "Haunsheim", null], - ["097735713153", "Medlingen", null], - ["097735714112", "Bachhagel", null], - ["097735714170", "Syrgenstein", null], - ["097735714187", "Zöschingen", null], - ["097735715147", "Mödingen", null], - ["097735715183", "Wittislingen, M", null], - ["097735715186", "Ziertheim", null], - ["097735716119", "Blindheim", null], - ["097735716139", "Höchstädt a.d.Donau, St", null], - ["097735716146", "Lutzingen", null], - ["097735716150", "Finningen", null], - ["097735716164", "Schwenningen", null], - ["097735718116", "Binswangen", null], - ["097735718143", "Laugna", null], - ["097735718179", "Villenbach", null], - ["097735718182", "Wertingen, St", null], - ["097735718188", "Zusamaltheim", null], - ["097735719111", "Aislingen, M", null], - ["097735719133", "Glött", null], - ["097735719140", "Holzheim", null], - ["097740116116", "Ursberg", null], - ["097740119119", "Bibertal", null], - ["097740121121", "Burgau, St", null], - ["097740122122", "Burtenbach, M", null], - ["097740135135", "Günzburg, GKSt", null], - ["097740144144", "Jettingen-Scheppach, M", null], - ["097740145145", "Kammeltal", null], - ["097740150150", "Krumbach (Schwaben), St", null], - ["097740155155", "Leipheim, St", null], - ["097740162162", "Neuburg a.d.Kammel, M", null], - ["097745727136", "Gundremmingen", null], - ["097745727171", "Offingen, M", null], - ["097745727174", "Rettenbach", null], - ["097745728127", "Dürrlauingen", null], - ["097745728140", "Haldenwang", null], - ["097745728151", "Landensberg", null], - ["097745728178", "Röfingen", null], - ["097745728196", "Winterbach", null], - ["097745729118", "Bubesheim", null], - ["097745729148", "Kötz", null], - ["097745730133", "Ellzee", null], - ["097745730143", "Ichenhausen, St", null], - ["097745730191", "Waldstetten, M", null], - ["097745731111", "Aletshausen", null], - ["097745731117", "Breitenthal", null], - ["097745731124", "Deisenhausen", null], - ["097745731129", "Ebershausen", null], - ["097745731189", "Wiesenbach", null], - ["097745731192", "Waltenhausen", null], - ["097745732115", "Balzhausen", null], - ["097745732160", "Münsterhausen, M", null], - ["097745732185", "Thannhausen, St", null], - ["097745733166", "Aichen", null], - ["097745733198", "Ziemetshausen, M", null], - ["097749451451", "Ebershauser-Nattenhauser Wald", null], - ["097749452452", "Winzerwald", null], - ["097750115115", "Bellenberg", null], - ["097750129129", "Illertissen, St", null], - ["097750134134", "Nersingen", null], - ["097750135135", "Neu-Ulm, GKSt", null], - ["097750139139", "Elchingen", null], - ["097750149149", "Roggenburg", null], - ["097750152152", "Senden, St", null], - ["097750162162", "Vöhringen, St", null], - ["097750164164", "Weißenhorn, St", null], - ["097755739126", "Holzheim", null], - ["097755739143", "Pfaffenhofen a.d.Roth, M", null], - ["097755740111", "Altenstadt, M", null], - ["097755740132", "Kellmünz a.d.Iller, M", null], - ["097755740142", "Osterberg", null], - ["097755741118", "Buch, M", null], - ["097755741141", "Oberroth", null], - ["097755741161", "Unterroth", null], - ["097759451451", "Auwald", null], - ["097759452452", "Oberroggenburger Wald", null], - ["097759454454", "Stoffenrieder Forst", null], - ["097759455455", "Unterroggenburger Wald", null], - ["097760111111", "Bodolz", null], - ["097760114114", "Heimenkirch, M", null], - ["097760116116", "Lindau (Bodensee), GKSt", null], - ["097760117117", "Lindenberg i.Allgäu, St", null], - ["097760120120", "Nonnenhorn", null], - ["097760122122", "Opfenbach", null], - ["097760125125", "Scheidegg, M", null], - ["097760128128", "Wasserburg (Bodensee)", null], - ["097760129129", "Weiler-Simmerberg, M", null], - ["097760131131", "Hergatz", null], - ["097765735115", "Hergensweiler", null], - ["097765735126", "Sigmarszell", null], - ["097765735130", "Weißensberg", null], - ["097765737112", "Gestratz", null], - ["097765737113", "Grünenbach", null], - ["097765737118", "Maierhöfen", null], - ["097765737124", "Röthenbach (Allgäu)", null], - ["097765738121", "Oberreute", null], - ["097765738127", "Stiefenhofen", null], - ["097770129129", "Füssen, St", null], - ["097770130130", "Germaringen", null], - ["097770147147", "Lechbruck am See", null], - ["097770151151", "Marktoberdorf, St", null], - ["097770152152", "Mauerstetten", null], - ["097770153153", "Nesselwang, M", null], - ["097770159159", "Pfronten", null], - ["097770165165", "Ronsberg, M", null], - ["097770169169", "Schwangau", null], - ["097770173173", "Halblech", null], - ["097775748121", "Buchloe, St", null], - ["097775748140", "Jengen", null], - ["097775748145", "Lamerdingen", null], - ["097775748177", "Waal, M", null], - ["097775749139", "Irsee, M", null], - ["097775749158", "Pforzen", null], - ["097775749164", "Rieden", null], - ["097775751141", "Kaltental, M", null], - ["097775751155", "Oberostendorf", null], - ["097775751157", "Osterzell", null], - ["097775751172", "Stöttwang", null], - ["097775751182", "Westendorf", null], - ["097775752111", "Aitrang", null], - ["097775752112", "Biessenhofen", null], - ["097775752118", "Bidingen", null], - ["097775752167", "Ruderatshofen", null], - ["097775753114", "Baisweil", null], - ["097775753124", "Eggenthal", null], - ["097775753128", "Friesenried", null], - ["097775754138", "Günzach", null], - ["097775754154", "Obergünzburg, M", null], - ["097775754176", "Untrasried", null], - ["097775755131", "Görisried", null], - ["097775755144", "Kraftisried", null], - ["097775755175", "Unterthingau, M", null], - ["097775756125", "Eisenberg", null], - ["097775756135", "Hopferau", null], - ["097775756149", "Lengenwang", null], - ["097775756168", "Rückholz", null], - ["097775756170", "Seeg", null], - ["097775756179", "Wald", null], - ["097775770163", "Rieden am Forggensee", null], - ["097775770166", "Roßhaupten", null], - ["097775772171", "Stötten a.Auerberg", null], - ["097775772183", "Rettenbach a.Auerberg", null], - ["097780116116", "Bad Wörishofen, St", null], - ["097780123123", "Buxheim", null], - ["097780137137", "Ettringen", null], - ["097780168168", "Markt Rettenbach, M", null], - ["097780169169", "Markt Wald, M", null], - ["097780173173", "Mindelheim, St", null], - ["097780196196", "Sontheim", null], - ["097780204204", "Tussenhausen, M", null], - ["097785757119", "Böhen", null], - ["097785757149", "Hawangen", null], - ["097785757186", "Ottobeuren, M", null], - ["097785758115", "Babenhausen, M", null], - ["097785758130", "Egg a.d.Günz", null], - ["097785758157", "Kirchhaslach", null], - ["097785758184", "Oberschönegg", null], - ["097785758217", "Winterrieden", null], - ["097785758221", "Kettershausen", null], - ["097785759121", "Breitenbrunn", null], - ["097785759183", "Oberrieden", null], - ["097785759187", "Pfaffenhausen, M", null], - ["097785759190", "Salgen", null], - ["097785760134", "Eppishausen", null], - ["097785760158", "Kirchheim i.Schw., M", null], - ["097785761120", "Boos", null], - ["097785761139", "Fellheim", null], - ["097785761150", "Heimertingen", null], - ["097785761177", "Niederrieden", null], - ["097785761188", "Pleß", null], - ["097785762136", "Erkheim, M", null], - ["097785762163", "Lauben", null], - ["097785762180", "Kammlach", null], - ["097785762214", "Westerheim", null], - ["097785764111", "Amberg", null], - ["097785764203", "Türkheim, M", null], - ["097785764209", "Rammingen", null], - ["097785764216", "Wiedergeltingen", null], - ["097785765118", "Benningen", null], - ["097785765151", "Holzgünz", null], - ["097785765162", "Lachen", null], - ["097785765171", "Memmingerberg", null], - ["097785765202", "Trunkelsberg", null], - ["097785765205", "Ungerhausen", null], - ["097785766113", "Apfeltrach", null], - ["097785766127", "Dirlewang, M", null], - ["097785766199", "Stetten", null], - ["097785766207", "Unteregg", null], - ["097785767161", "Kronburg", null], - ["097785767164", "Lautrach", null], - ["097785767165", "Legau, M", null], - ["097785768144", "Bad Grönenbach, M", null], - ["097785768218", "Wolfertschwenden", null], - ["097785768219", "Woringen", null], - ["097789451451", "Ungerhauser Wald", null], - ["097790115115", "Asbach-Bäumenheim", null], - ["097790131131", "Donauwörth, GKSt", null], - ["097790147147", "Fremdingen", null], - ["097790155155", "Harburg (Schwaben), St", null], - ["097790169169", "Kaisheim, M", null], - ["097790178178", "Marxheim", null], - ["097790181181", "Mertingen", null], - ["097790185185", "Möttingen", null], - ["097790194194", "Nördlingen, GKSt", null], - ["097790196196", "Oberndorf a.Lech", null], - ["097790218218", "Tapfheim", null], - ["097795720176", "Maihingen", null], - ["097795720177", "Marktoffingen", null], - ["097795720224", "Wallerstein, M", null], - ["097795721117", "Auhausen", null], - ["097795721138", "Ehingen a.Ries", null], - ["097795721154", "Hainsfarth", null], - ["097795721180", "Megesheim", null], - ["097795721188", "Munningen", null], - ["097795721197", "Oettingen i.Bay., St", null], - ["097795722111", "Alerheim", null], - ["097795722112", "Amerdingen", null], - ["097795722130", "Deiningen", null], - ["097795722136", "Ederheim", null], - ["097795722146", "Forheim", null], - ["097795722162", "Hohenaltheim", null], - ["097795722184", "Mönchsdeggingen", null], - ["097795722203", "Reimlingen", null], - ["097795722226", "Wechingen", null], - ["097795723148", "Fünfstetten", null], - ["097795723167", "Huisheim", null], - ["097795723198", "Otting", null], - ["097795723228", "Wemding, St", null], - ["097795723231", "Wolferstadt", null], - ["097795724126", "Buchdorf", null], - ["097795724129", "Daiting", null], - ["097795724186", "Monheim, St", null], - ["097795724206", "Rögling", null], - ["097795724217", "Tagmersheim", null], - ["097795725149", "Genderkingen", null], - ["097795725163", "Holzheim", null], - ["097795725187", "Münster", null], - ["097795725192", "Niederschönenfeld", null], - ["097795725201", "Rain, St", null], - ["097799452452", "Dornstadt-Linkersbaindt", null], - ["097799453453", "Esterholz", null], - ["097800112112", "Altusried, M", null], - ["097800114114", "Betzigau", null], - ["097800115115", "Blaichach", null], - ["097800117117", "Buchenberg, M", null], - ["097800118118", "Burgberg i.Allgäu", null], - ["097800119119", "Dietmannsried, M", null], - ["097800120120", "Durach", null], - ["097800122122", "Haldenwang", null], - ["097800123123", "Bad Hindelang, M", null], - ["097800124124", "Immenstadt i.Allgäu, St", null], - ["097800125125", "Lauben", null], - ["097800128128", "Oy-Mittelberg", null], - ["097800132132", "Oberstaufen, M", null], - ["097800133133", "Oberstdorf, M", null], - ["097800137137", "Rettenberg", null], - ["097800139139", "Sonthofen, St", null], - ["097800140140", "Sulzberg, M", null], - ["097800143143", "Waltenhofen", null], - ["097800145145", "Wertach, M", null], - ["097800146146", "Wiggensbach, M", null], - ["097800147147", "Wildpoldsried", null], - ["097805742113", "Balderschwang", null], - ["097805742116", "Bolsterlang", null], - ["097805742121", "Fischen i.Allgäu", null], - ["097805742131", "Obermaiselstein", null], - ["097805742134", "Ofterschwang", null], - ["097805745127", "Missen-Wilhams", null], - ["097805745144", "Weitnau, M", null], - ["097809451451", "Kempter Wald", null], - ["100410100100", "Saarbrücken, Landeshauptstadt", null], - ["100410511511", "Friedrichsthal, Stadt", null], - ["100410512512", "Großrosseln", null], - ["100410513513", "Heusweiler", null], - ["100410514514", "Kleinblittersdorf", null], - ["100410515515", "Püttlingen, Stadt", null], - ["100410516516", "Quierschied", null], - ["100410517517", "Riegelsberg", null], - ["100410518518", "Sulzbach/ Saar, Stadt", null], - ["100410519519", "Völklingen, Stadt", null], - ["100420111111", "Beckingen", null], - ["100420112112", "Losheim am See", null], - ["100420113113", "Merzig, Kreisstadt", null], - ["100420114114", "Mettlach", null], - ["100420115115", "Perl", null], - ["100420116116", "Wadern, Stadt", null], - ["100420117117", "Weiskirchen", null], - ["100429999999", "Deutsch-luxemburgisches Hoheitsgebiet", null], - ["100430111111", "Eppelborn", null], - ["100430112112", "Illingen", null], - ["100430113113", "Merchweiler", null], - ["100430114114", "Neunkirchen, Kreisstadt", null], - ["100430115115", "Ottweiler, Stadt", null], - ["100430116116", "Schiffweiler", null], - ["100430117117", "Spiesen-Elversberg", null], - ["100440111111", "Dillingen/ Saar, Stadt", null], - ["100440112112", "Lebach, Stadt", null], - ["100440113113", "Nalbach", null], - ["100440114114", "Rehlingen-Siersburg", null], - ["100440115115", "Saarlouis, Kreisstadt", null], - ["100440116116", "Saarwellingen", null], - ["100440117117", "Schmelz", null], - ["100440118118", "Schwalbach", null], - ["100440119119", "Überherrn", null], - ["100440120120", "Wadgassen", null], - ["100440121121", "Wallerfangen", null], - ["100440122122", "Bous", null], - ["100440123123", "Ensdorf", null], - ["100450111111", "Bexbach, Stadt", null], - ["100450112112", "Blieskastel, Stadt", null], - ["100450113113", "Gersheim", null], - ["100450114114", "Homburg, Kreisstadt", null], - ["100450115115", "Kirkel", null], - ["100450116116", "Mandelbachtal", null], - ["100450117117", "St. Ingbert, Stadt", null], - ["100460111111", "Freisen", null], - ["100460112112", "Marpingen", null], - ["100460113113", "Namborn", null], - ["100460114114", "Nohfelden", null], - ["100460115115", "Nonnweiler", null], - ["100460116116", "Oberthal", null], - ["100460117117", "St. Wendel, Kreisstadt", null], - ["100460118118", "Tholey", null], - ["110000000000", "Berlin, Stadt", null], - ["110010001001", "Mitte", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "110020002002", - "Friedrichshain-Kreuzberg", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["110030003003", "Pankow", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "110040004004", - "Charlottenburg-Wilmersdorf", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["110050005005", "Spandau", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["110060006006", "Steglitz-Zehlendorf", "Stadt-/Ortsteil bzw. Stadtbezirk"], - [ - "110070007007", - "Tempelhof-Schöneberg", - "Stadt-/Ortsteil bzw. Stadtbezirk" - ], - ["110080008008", "Neukölln", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["110090009009", "Treptow-Köpenick", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["110100010010", "Marzahn-Hellersdorf", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["110110011011", "Lichtenberg", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["110120012012", "Reinickendorf", "Stadt-/Ortsteil bzw. Stadtbezirk"], - ["120510000000", "Brandenburg an der Havel, Stadt", null], - ["120520000000", "Cottbus/Chóśebuz, Stadt", null], - ["120530000000", "Frankfurt (Oder), Stadt", null], - ["120540000000", "Potsdam, Stadt", null], - ["120600005005", "Ahrensfelde", null], - ["120600020020", "Bernau bei Berlin, Stadt", null], - ["120600052052", "Eberswalde, Stadt", null], - ["120600181181", "Panketal", null], - ["120600198198", "Schorfheide", null], - ["120600269269", "Wandlitz", null], - ["120600280280", "Werneuchen, Stadt", null], - ["120605003024", "Biesenthal, Stadt", null], - ["120605003034", "Breydin", null], - ["120605003154", "Marienwerder", null], - ["120605003161", "Melchow", null], - ["120605003192", "Rüdnitz", null], - ["120605003250", "Sydower Fließ", null], - ["120605006012", "Althüttendorf", null], - ["120605006068", "Friedrichswalde", null], - ["120605006100", "Joachimsthal, Stadt", null], - ["120605006296", "Ziethen", null], - ["120605011036", "Britz", null], - ["120605011045", "Chorin", null], - ["120605011092", "Hohenfinow", null], - ["120605011128", "Liepe", null], - ["120605011149", "Lunow-Stolzenhagen", null], - ["120605011172", "Niederfinow", null], - ["120605011176", "Oderberg, Stadt", null], - ["120605011185", "Parsteinsee", null], - ["120610020020", "Bestensee", null], - ["120610112112", "Eichwalde", null], - ["120610217217", "Heidesee", null], - ["120610219219", "Heideblick", null], - ["120610260260", "Königs Wusterhausen, Stadt", null], - ["120610316316", "Lübben (Spreewald) / Lubin (Błota), Stadt", null], - ["120610320320", "Luckau, Stadt", null], - ["120610329329", "Märkische Heide/Markojska Góla", null], - ["120610332332", "Mittenwalde, Stadt", null], - ["120610433433", "Schönefeld", null], - ["120610444444", "Schulzendorf", null], - ["120610540540", "Wildau, Stadt", null], - ["120610572572", "Zeuthen", null], - ["120615108192", "Groß Köris", null], - ["120615108216", "Halbe", null], - ["120615108328", "Märkisch Buchholz, Stadt", null], - ["120615108344", "Münchehofe", null], - ["120615108448", "Schwerin", null], - ["120615108492", "Teupitz, Stadt", null], - ["120615113005", "Alt Zauche-Wußwerk/Stara Niwa-Wózwjerch", null], - ["120615113061", "Byhleguhre-Byhlen/Beła Góra-Bělin", null], - ["120615113224", "Jamlitz", null], - ["120615113308", "Lieberose, Stadt", null], - ["120615113352", "Neu Zauche/Nowa Niwa", null], - ["120615113450", "Schwielochsee/Gójacki Jazor", null], - ["120615113470", "Spreewaldheide/Błośańska Góla", null], - ["120615113476", "Straupitz (Spreewald)/Tšupc (Błota)", null], - ["120615114017", "Bersteland", null], - ["120615114097", "Drahnsdorf", null], - ["120615114164", "Golßen, Stadt", null], - ["120615114244", "Kasel-Golzig", null], - ["120615114265", "Krausnick-Groß Wasserburg", null], - ["120615114405", "Rietzneuendorf-Staakow", null], - ["120615114428", "Schlepzig/Słopišća", null], - ["120615114435", "Schönwald", null], - ["120615114471", "Steinreich", null], - ["120615114510", "Unterspreewald", null], - ["120620092092", "Doberlug-Kirchhain, Stadt", null], - ["120620124124", "Elsterwerda, Stadt", null], - ["120620140140", "Finsterwalde, Stadt", null], - ["120620224224", "Herzberg (Elster), Stadt", null], - ["120620410410", "Röderland", null], - ["120620461461", "Schönewalde, Stadt", null], - ["120620469469", "Sonnewalde, Stadt", null], - ["120625031024", "Bad Liebenwerda, Stadt", null], - ["120625031128", "Falkenberg/Elster, Stadt", null], - ["120625031341", "Mühlberg/Elbe, Stadt", null], - ["120625031500", "Uebigau-Wahrenbrück, Stadt", null], - ["120625202219", "Heideland", null], - ["120625202417", "Rückersdorf", null], - ["120625202440", "Schilda", null], - ["120625202453", "Schönborn", null], - ["120625202492", "Tröbitz", null], - ["120625205088", "Crinitz", null], - ["120625205293", "Lichterfeld-Schacksdorf", null], - ["120625205333", "Massen-Niederlausitz", null], - ["120625205425", "Sallgast", null], - ["120625207177", "Gorden-Staupitz", null], - ["120625207240", "Hohenleipisch", null], - ["120625207372", "Plessa", null], - ["120625207464", "Schraden", null], - ["120625209134", "Fichtwald", null], - ["120625209237", "Hohenbucko", null], - ["120625209282", "Kremitzaue", null], - ["120625209289", "Lebusa", null], - ["120625209445", "Schlieben, Stadt", null], - ["120625211196", "Gröden", null], - ["120625211208", "Großthiemig", null], - ["120625211232", "Hirschfeld", null], - ["120625211336", "Merzdorf", null], - ["120630036036", "Brieselang", null], - ["120630056056", "Dallgow-Döberitz", null], - ["120630080080", "Falkensee, Stadt", null], - ["120630148148", "Ketzin/Havel, Stadt", null], - ["120630189189", "Milower Land", null], - ["120630208208", "Nauen, Stadt", null], - ["120630244244", "Premnitz, Stadt", null], - ["120630252252", "Rathenow, Stadt", null], - ["120630273273", "Schönwalde-Glien", null], - ["120630357357", "Wustermark", null], - ["120635302088", "Friesack, Stadt", null], - ["120635302142", "Wiesenaue", null], - ["120635302202", "Mühlenberge", null], - ["120635302228", "Paulinenaue", null], - ["120635302240", "Pessin", null], - ["120635302256", "Retzow", null], - ["120635306165", "Kotzen", null], - ["120635306186", "Märkisch Luch", null], - ["120635306212", "Nennhausen", null], - ["120635306293", "Stechow-Ferchesar", null], - ["120635309094", "Gollenberg", null], - ["120635309112", "Großderschau", null], - ["120635309134", "Havelaue", null], - ["120635309161", "Kleßen-Görne", null], - ["120635309260", "Rhinow, Stadt", null], - ["120635309274", "Seeblick", null], - ["120640029029", "Altlandsberg, Stadt", null], - ["120640044044", "Bad Freienwalde (Oder), Stadt", null], - ["120640136136", "Fredersdorf-Vogelsdorf", null], - ["120640227227", "Hoppegarten", null], - ["120640274274", "Letschin", null], - ["120640317317", "Müncheberg, Stadt", null], - ["120640336336", "Neuenhagen bei Berlin", null], - ["120640380380", "Petershagen/Eggersdorf", null], - ["120640428428", "Rüdersdorf bei Berlin", null], - ["120640448448", "Seelow, Stadt", null], - ["120640472472", "Strausberg, Stadt", null], - ["120640512512", "Wriezen, Stadt", null], - ["120645403053", "Beiersdorf-Freudenberg", null], - ["120645403125", "Falkenberg", null], - ["120645403205", "Heckelberg-Brunow", null], - ["120645403222", "Höhenland", null], - ["120645404009", "Alt Tucheband", null], - ["120645404057", "Bleyen-Genschmar", null], - ["120645404172", "Golzow", null], - ["120645404266", "Küstriner Vorland", null], - ["120645404538", "Zechin", null], - ["120645406268", "Lebus, Stadt", null], - ["120645406388", "Podelzig", null], - ["120645406420", "Reitwein", null], - ["120645406480", "Treplin", null], - ["120645406539", "Zeschdorf", null], - ["120645408084", "Buckow (Märkische Schweiz), Stadt", null], - ["120645408153", "Garzau-Garzin", null], - ["120645408370", "Oberbarnim", null], - ["120645408408", "Rehfelde", null], - ["120645408484", "Waldsieversdorf", null], - ["120645410190", "Gusow-Platkow", null], - ["120645410303", "Märkische Höhe", null], - ["120645410340", "Neuhardenberg", null], - ["120645412128", "Falkenhagen (Mark)", null], - ["120645412130", "Fichtenhöhe", null], - ["120645412288", "Lietzen", null], - ["120645412290", "Lindendorf", null], - ["120645412482", "Vierlinden", null], - ["120645414061", "Bliesdorf", null], - ["120645414349", "Neulewin", null], - ["120645414365", "Neutrebbin", null], - ["120645414371", "Oderaue", null], - ["120645414393", "Prötzel", null], - ["120645414417", "Reichenow-Möglin", null], - ["120650036036", "Birkenwerder", null], - ["120650084084", "Fürstenberg/Havel, Stadt", null], - ["120650096096", "Glienicke/Nordbahn", null], - ["120650136136", "Hennigsdorf, Stadt", null], - ["120650144144", "Hohen Neuendorf, Stadt", null], - ["120650165165", "Kremmen, Stadt", null], - ["120650180180", "Leegebruch", null], - ["120650193193", "Liebenwalde, Stadt", null], - ["120650198198", "Löwenberger Land", null], - ["120650225225", "Mühlenbecker Land", null], - ["120650251251", "Oberkrämer", null], - ["120650256256", "Oranienburg, Stadt", null], - ["120650332332", "Velten, Stadt", null], - ["120650356356", "Zehdenick, Stadt", null], - ["120655502100", "Gransee, Stadt", null], - ["120655502117", "Großwoltersdorf", null], - ["120655502276", "Schönermark", null], - ["120655502301", "Sonnenberg", null], - ["120655502310", "Stechlin", null], - ["120660052052", "Calau/Kalawa, Stadt", null], - ["120660112112", "Großräschen/Rań, Stadt", null], - ["120660176176", "Lauchhammer, Stadt", null], - ["120660196196", "Lübbenau/Spreewald / Lubnjow/Błota, Stadt", null], - ["120660285285", "Schipkau", null], - ["120660296296", "Schwarzheide, Stadt", null], - ["120660304304", "Senftenberg/Zły Komorow, Stadt", null], - ["120660320320", "Vetschau/Spreewald / Wětošow/Błota, Stadt", null], - ["120665601008", "Altdöbern", null], - ["120665601041", "Bronkow", null], - ["120665601202", "Luckaitztal", null], - ["120665601226", "Neu-Seeland/Nowa Jazorina", null], - ["120665601228", "Neupetershain/Nowe Wiki", null], - ["120665606064", "Frauendorf", null], - ["120665606104", "Großkmehlen", null], - ["120665606168", "Kroppen", null], - ["120665606188", "Lindenau", null], - ["120665606240", "Ortrand, Stadt", null], - ["120665606316", "Tettau", null], - ["120665607116", "Grünewald", null], - ["120665607120", "Guteborn", null], - ["120665607124", "Hermsdorf", null], - ["120665607132", "Hohenbocka", null], - ["120665607272", "Ruhland, Stadt", null], - ["120665607292", "Schwarzbach", null], - ["120670036036", "Beeskow, Stadt", null], - ["120670120120", "Eisenhüttenstadt, Stadt", null], - ["120670124124", "Erkner, Stadt", null], - ["120670137137", "Friedland, Stadt", null], - ["120670144144", "Fürstenwalde/Spree, Stadt", null], - ["120670201201", "Grünheide (Mark)", null], - ["120670426426", "Rietz-Neuendorf", null], - ["120670440440", "Schöneiche bei Berlin", null], - ["120670481481", "Storkow (Mark), Stadt", null], - ["120670493493", "Tauche", null], - ["120670544544", "Woltersdorf", null], - ["120675701076", "Brieskow-Finkenheerd", null], - ["120675701180", "Groß Lindow", null], - ["120675701508", "Vogelsang", null], - ["120675701528", "Wiesenau", null], - ["120675701552", "Ziltendorf", null], - ["120675705292", "Lawitz", null], - ["120675705338", "Neißemünde", null], - ["120675705357", "Neuzelle", null], - ["120675706040", "Berkenbrück", null], - ["120675706072", "Briesen (Mark)", null], - ["120675706237", "Jacobsdorf", null], - ["120675706473", "Steinhöfel", null], - ["120675707024", "Bad Saarow", null], - ["120675707112", "Diensdorf-Radlow", null], - ["120675707288", "Langewahl", null], - ["120675707413", "Reichenwalde", null], - ["120675707520", "Wendisch Rietz", null], - ["120675708205", "Grunow-Dammendorf", null], - ["120675708324", "Mixdorf", null], - ["120675708336", "Müllrose, Stadt", null], - ["120675708397", "Ragow-Merz", null], - ["120675708438", "Schlaubetal", null], - ["120675708458", "Siehdichum", null], - ["120675709173", "Gosen-Neu Zittau", null], - ["120675709408", "Rauen", null], - ["120675709469", "Spreenhagen", null], - ["120680117117", "Fehrbellin", null], - ["120680181181", "Heiligengrabe", null], - ["120680264264", "Kyritz, Stadt", null], - ["120680320320", "Neuruppin, Stadt", null], - ["120680353353", "Rheinsberg, Stadt", null], - ["120680468468", "Wittstock/Dosse, Stadt", null], - ["120680477477", "Wusterhausen/Dosse", null], - ["120685804188", "Herzberg (Mark)", null], - ["120685804280", "Lindow (Mark), Stadt", null], - ["120685804372", "Rüthnick", null], - ["120685804437", "Vielitzsee", null], - ["120685805052", "Breddin", null], - ["120685805109", "Dreetz", null], - ["120685805324", "Neustadt (Dosse), Stadt", null], - ["120685805409", "Sieversdorf-Hohenofen", null], - ["120685805417", "Stüdenitz-Schönermark", null], - ["120685805501", "Zernitz-Lohm", null], - ["120685807072", "Dabergotz", null], - ["120685807306", "Märkisch Linden", null], - ["120685807413", "Storbeck-Frankendorf", null], - ["120685807425", "Temnitzquell", null], - ["120685807426", "Temnitztal", null], - ["120685807452", "Walsleben", null], - ["120690017017", "Beelitz, Stadt", null], - ["120690020020", "Bad Belzig, Stadt", null], - ["120690249249", "Groß Kreutz (Havel)", null], - ["120690304304", "Kleinmachnow", null], - ["120690306306", "Kloster Lehnin", null], - ["120690397397", "Michendorf", null], - ["120690454454", "Nuthetal", null], - ["120690590590", "Schwielowsee", null], - ["120690596596", "Seddiner See", null], - ["120690604604", "Stahnsdorf", null], - ["120690616616", "Teltow, Stadt", null], - ["120690632632", "Treuenbrietzen, Stadt", null], - ["120690656656", "Werder (Havel), Stadt", null], - ["120690665665", "Wiesenburg/Mark", null], - ["120695902018", "Beetzsee", null], - ["120695902019", "Beetzseeheide", null], - ["120695902270", "Havelsee, Stadt", null], - ["120695902460", "Päwesin", null], - ["120695902541", "Roskow", null], - ["120695904052", "Borkheide", null], - ["120695904056", "Borkwalde", null], - ["120695904076", "Brück, Stadt", null], - ["120695904216", "Golzow", null], - ["120695904345", "Linthe", null], - ["120695904470", "Planebruch", null], - ["120695910402", "Mühlenfließ", null], - ["120695910448", "Niemegk, Stadt", null], - ["120695910474", "Planetal", null], - ["120695910485", "Rabenstein/Fläming", null], - ["120695917028", "Bensdorf", null], - ["120695917537", "Rosenau", null], - ["120695917688", "Wusterwitz", null], - ["120695918089", "Buckautal", null], - ["120695918224", "Görzke", null], - ["120695918232", "Gräben", null], - ["120695918648", "Wenzlow", null], - ["120695918680", "Wollin", null], - ["120695918696", "Ziesar, Stadt", null], - ["120700125125", "Groß Pankow (Prignitz)", null], - ["120700149149", "Gumtow", null], - ["120700173173", "Karstädt", null], - ["120700296296", "Perleberg, Stadt", null], - ["120700302302", "Plattenburg", null], - ["120700316316", "Pritzwalk, Stadt", null], - ["120700424424", "Wittenberge, Stadt", null], - ["120705001008", "Bad Wilsnack, Stadt", null], - ["120705001052", "Breese", null], - ["120705001241", "Legde/Quitzöbel", null], - ["120705001348", "Rühstädt", null], - ["120705001416", "Weisen", null], - ["120705005060", "Cumlosen", null], - ["120705005236", "Lanz", null], - ["120705005244", "Lenzen (Elbe), Stadt", null], - ["120705005246", "Lenzerwische", null], - ["120705006096", "Gerdshagen", null], - ["120705006153", "Halenbeck-Rohlsdorf", null], - ["120705006222", "Kümmernitztal", null], - ["120705006266", "Marienfließ", null], - ["120705006280", "Meyenburg, Stadt", null], - ["120705009028", "Berge", null], - ["120705009145", "Gülitz-Reetz", null], - ["120705009300", "Pirow", null], - ["120705009325", "Putlitz, Stadt", null], - ["120705009393", "Triglitz", null], - ["120710057057", "Drebkau/Drjowk, Stadt", null], - ["120710076076", "Forst (Lausitz)/Baršć (Łužyca), Stadt", null], - ["120710160160", "Guben, Stadt", null], - ["120710244244", "Kolkwitz/Gołkojce", null], - ["120710301301", "Neuhausen/Spree / Kopańce/Sprjewja", null], - ["120710337337", "Schenkendöbern/Derbno", null], - ["120710372372", "Spremberg/Grodk, Stadt", null], - ["120710408408", "Welzow/Wjelcej, Stadt", null], - ["120715101028", "Briesen/Brjazyna", null], - ["120715101032", "Burg (Spreewald)/Bórkowy (Błota)", null], - ["120715101041", "Dissen-Striesow/Dešno-Strjažow", null], - ["120715101164", "Guhrow/Góry", null], - ["120715101341", "Schmogrow-Fehrow/Smogorjow-Prjawoz", null], - ["120715101412", "Werben/Wjerbno", null], - ["120715102044", "Döbern/Derbno, Stadt", null], - ["120715102074", "Felixsee/Feliksowy Jazor", null], - ["120715102153", "Groß Schacksdorf-Simmersdorf", null], - ["120715102189", "Jämlitz-Klein Düben", null], - ["120715102294", "Neiße-Malxetal/Dolina Nysa-Małksa", null], - ["120715102392", "Tschernitz/Cersk", null], - ["120715102414", "Wiesengrund/Łukojce", null], - ["120715107052", "Drachhausen/Hochoza", null], - ["120715107060", "Drehnow/Drjenow", null], - ["120715107176", "Heinersbrück/Móst", null], - ["120715107193", "Jänschwalde/Janšojce", null], - ["120715107304", "Peitz/Picnjo, Stadt", null], - ["120715107384", "Tauer/Turjej", null], - ["120715107386", "Teichland/Gatojce", null], - ["120715107401", "Turnow-Preilack/Turnow-Pśiłuk", null], - ["120720002002", "Am Mellensee", null], - ["120720014014", "Baruth/Mark, Stadt", null], - ["120720017017", "Blankenfelde-Mahlow", null], - ["120720120120", "Großbeeren", null], - ["120720169169", "Jüterbog, Stadt", null], - ["120720232232", "Luckenwalde, Stadt", null], - ["120720240240", "Ludwigsfelde, Stadt", null], - ["120720297297", "Niedergörsdorf", null], - ["120720312312", "Nuthe-Urstromtal", null], - ["120720340340", "Rangsdorf", null], - ["120720426426", "Trebbin, Stadt", null], - ["120720477477", "Zossen, Stadt", null], - ["120725204053", "Dahme/Mark, Stadt", null], - ["120725204055", "Dahmetal", null], - ["120725204157", "Ihlow", null], - ["120725204298", "Niederer Fläming", null], - ["120730008008", "Angermünde, Stadt", null], - ["120730069069", "Boitzenburger Land", null], - ["120730384384", "Lychen, Stadt", null], - ["120730429429", "Nordwestuckermark", null], - ["120730452452", "Prenzlau, Stadt", null], - ["120730532532", "Schwedt/Oder, Stadt", null], - ["120730572572", "Templin, Stadt", null], - ["120730579579", "Uckerland", null], - ["120735303085", "Brüssow, Stadt", null], - ["120735303093", "Carmzow-Wallmow", null], - ["120735303216", "Göritz", null], - ["120735303490", "Schenkenberg", null], - ["120735303520", "Schönfeld", null], - ["120735304097", "Casekow", null], - ["120735304189", "Gartz (Oder), Stadt", null], - ["120735304309", "Hohenselchow-Groß Pinnow", null], - ["120735304393", "Mescherin", null], - ["120735304565", "Tantow", null], - ["120735305157", "Flieth-Stegelitz", null], - ["120735305201", "Gerswalde", null], - ["120735305396", "Milmersdorf", null], - ["120735305404", "Mittenwalde", null], - ["120735305569", "Temmen-Ringenwalde", null], - ["120735306225", "Gramzow", null], - ["120735306261", "Grünow", null], - ["120735306430", "Oberuckersee", null], - ["120735306458", "Randowtal", null], - ["120735306578", "Uckerfelde", null], - ["120735306645", "Zichow", null], - ["120735310032", "Berkholz-Meyenburg", null], - ["120735310386", "Mark Landin", null], - ["120735310440", "Pinnow", null], - ["120735310603", "Passow", null], - ["130009999999", "Küstengewässer einschl. Anteil am Festlandsockel", null], - ["130030000000", "Rostock, Hanse- und Universitätsstadt", null], - ["130040000000", "Schwerin, Landeshauptstadt", null], - ["130710027027", "Dargun, Stadt", null], - ["130710029029", "Demmin, Hansestadt", null], - ["130710033033", "Feldberger Seenlandschaft", null], - ["130710107107", "Neubrandenburg, Vier-Tore-Stadt", null], - ["130710110110", "Neustrelitz, Residenzstadt", null], - ["130710156156", "Waren (Müritz), Stadt", null], - ["130715151008", "Beggerow", null], - ["130715151014", "Borrentin", null], - ["130715151064", "Hohenbollentin", null], - ["130715151065", "Hohenmocker", null], - ["130715151072", "Kentzlin", null], - ["130715151076", "Kletzin", null], - ["130715151089", "Lindenberg", null], - ["130715151096", "Meesiger", null], - ["130715151112", "Nossendorf", null], - ["130715151128", "Sarow", null], - ["130715151131", "Schönfeld", null], - ["130715151136", "Siedenbrünzow", null], - ["130715151139", "Sommersdorf", null], - ["130715151148", "Utzedel", null], - ["130715151150", "Verchen", null], - ["130715151157", "Warrenzin", null], - ["130715152028", "Datzetal", null], - ["130715152035", "Friedland, Stadt", null], - ["130715152037", "Galenbeck", null], - ["130715153007", "Basedow", null], - ["130715153032", "Faulenrost", null], - ["130715153039", "Gielow", null], - ["130715153084", "Kummerow", null], - ["130715153092", "Malchin, Stadt", null], - ["130715153109", "Neukalen, Peenestadt", null], - ["130715154001", "Alt Schwerin", null], - ["130715154036", "Fünfseen", null], - ["130715154043", "Göhren-Lebbin", null], - ["130715154093", "Malchow, Inselstadt", null], - ["130715154113", "Nossentiner Hütte", null], - ["130715154114", "Penkow", null], - ["130715154138", "Silz", null], - ["130715154155", "Walow", null], - ["130715154171", "Zislow", null], - ["130715155099", "Mirow, Stadt", null], - ["130715155119", "Priepert", null], - ["130715155159", "Wesenberg, Stadt", null], - ["130715155167", "Wustrow", null], - ["130715156011", "Blankensee", null], - ["130715156012", "Blumenholz", null], - ["130715156025", "Carpin", null], - ["130715156042", "Godendorf", null], - ["130715156058", "Grünow", null], - ["130715156066", "Hohenzieritz", null], - ["130715156075", "Klein Vielen", null], - ["130715156080", "Kratzeburg", null], - ["130715156100", "Möllenbeck", null], - ["130715156147", "Userin", null], - ["130715156162", "Wokuhl-Dabelow", null], - ["130715157009", "Beseritz", null], - ["130715157010", "Blankenhof", null], - ["130715157019", "Brunn", null], - ["130715157104", "Neddemin", null], - ["130715157108", "Neuenkirchen", null], - ["130715157111", "Neverin", null], - ["130715157140", "Sponholz", null], - ["130715157141", "Staven", null], - ["130715157145", "Trollenhagen", null], - ["130715157161", "Woggersin", null], - ["130715157166", "Wulkenzin", null], - ["130715157170", "Zirzow", null], - ["130715158005", "Ankershagen, Schliemanngemeinde", null], - ["130715158101", "Möllenhagen", null], - ["130715158115", "Penzlin, Stadt", null], - ["130715158173", "Kuckssee", null], - ["130715159003", "Altenhof", null], - ["130715159013", "Bollewick", null], - ["130715159020", "Buchholz", null], - ["130715159023", "Bütow", null], - ["130715159034", "Fincken", null], - ["130715159045", "Gotthun", null], - ["130715159053", "Groß Kelle", null], - ["130715159073", "Kieve", null], - ["130715159087", "Lärz", null], - ["130715159088", "Leizen", null], - ["130715159097", "Melz", null], - ["130715159118", "Priborn", null], - ["130715159122", "Rechlin", null], - ["130715159124", "Röbel/Müritz, Stadt", null], - ["130715159133", "Schwarz", null], - ["130715159137", "Sietow", null], - ["130715159143", "Stuer", null], - ["130715159175", "Eldetal", null], - ["130715159176", "Südmüritz", null], - ["130715160047", "Grabowhöfe", null], - ["130715160056", "Groß Plasten", null], - ["130715160063", "Hohen Wangelin", null], - ["130715160069", "Jabel", null], - ["130715160071", "Kargow", null], - ["130715160077", "Klink", null], - ["130715160078", "Klocksin", null], - ["130715160103", "Moltzow", null], - ["130715160144", "Torgelow am See", null], - ["130715160154", "Vollrathsruhe", null], - ["130715160172", "Peenehagen", null], - ["130715160174", "Schloen-Dratow", null], - ["130715161021", "Burg Stargard, Stadt", null], - ["130715161026", "Cölpin", null], - ["130715161055", "Groß Nemerow", null], - ["130715161067", "Holldorf", null], - ["130715161090", "Lindetal", null], - ["130715161117", "Pragsdorf", null], - ["130715162015", "Bredenfelde", null], - ["130715162018", "Briggow", null], - ["130715162048", "Grammentin", null], - ["130715162060", "Gülzow", null], - ["130715162068", "Ivenack", null], - ["130715162070", "Jürgenstorf", null], - ["130715162074", "Kittendorf", null], - ["130715162079", "Knorrendorf", null], - ["130715162102", "Mölln", null], - ["130715162123", "Ritzerow", null], - ["130715162127", "Rosenow", null], - ["130715162142", "Stavenhagen, Reuterstadt, Stadt", null], - ["130715162169", "Zettemin", null], - ["130715163002", "Altenhagen", null], - ["130715163004", "Altentreptow, Stadt", null], - ["130715163006", "Bartow", null], - ["130715163016", "Breesen", null], - ["130715163017", "Breest", null], - ["130715163022", "Burow", null], - ["130715163041", "Gnevkow", null], - ["130715163044", "Golchen", null], - ["130715163049", "Grapzow", null], - ["130715163050", "Grischow", null], - ["130715163057", "Groß Teetzleben", null], - ["130715163059", "Gültz", null], - ["130715163081", "Kriesow", null], - ["130715163120", "Pripsleben", null], - ["130715163125", "Röckwitz", null], - ["130715163135", "Siedenbollentin", null], - ["130715163146", "Tützpatz", null], - ["130715163158", "Werder", null], - ["130715163160", "Wildberg", null], - ["130715163163", "Wolde", null], - ["130715164054", "Groß Miltzow", null], - ["130715164083", "Kublank", null], - ["130715164105", "Neetzka", null], - ["130715164130", "Schönbeck", null], - ["130715164132", "Schönhausen", null], - ["130715164153", "Voigtsdorf", null], - ["130715164164", "Woldegk, Windmühlenstadt", null], - ["130720006006", "Bad Doberan, Stadt", null], - ["130720029029", "Dummerstorf", null], - ["130720036036", "Graal-Müritz, Ostseeheilbad", null], - ["130720043043", "Güstrow, Barlachstadt", null], - ["130720058058", "Kröpelin, Stadt", null], - ["130720060060", "Kühlungsborn, Ostseebad, Stadt", null], - ["130720074074", "Neubukow, Stadt", null], - ["130720091091", "Sanitz", null], - ["130720093093", "Satow", null], - ["130720106106", "Teterow, Bergringstadt", null], - ["130725251001", "Admannshagen-Bargeshagen", null], - ["130725251007", "Bartenshagen-Parkentin", null], - ["130725251017", "Börgerende-Rethwisch", null], - ["130725251047", "Hohenfelde", null], - ["130725251075", "Nienhagen, Ostseebad", null], - ["130725251083", "Reddelich", null], - ["130725251086", "Retschow", null], - ["130725251099", "Steffenshagen", null], - ["130725251117", "Wittenbeck", null], - ["130725252009", "Baumgarten", null], - ["130725252013", "Bernitt", null], - ["130725252020", "Bützow, Stadt", null], - ["130725252028", "Dreetz", null], - ["130725252050", "Jürgenshagen", null], - ["130725252053", "Klein Belitz", null], - ["130725252078", "Penzin", null], - ["130725252089", "Rühn", null], - ["130725252101", "Steinhagen", null], - ["130725252104", "Tarnow", null], - ["130725252114", "Warnow", null], - ["130725252120", "Zepelin", null], - ["130725253019", "Broderstorf", null], - ["130725253081", "Poppendorf", null], - ["130725253087", "Roggentin", null], - ["130725253108", "Thulendorf", null], - ["130725254004", "Altkalen", null], - ["130725254010", "Behren-Lübchin", null], - ["130725254031", "Finkenthal", null], - ["130725254035", "Gnoien, Warbelstadt", null], - ["130725254111", "Walkendorf", null], - ["130725255033", "Glasewitz", null], - ["130725255039", "Groß Schwiesow", null], - ["130725255042", "Gülzow-Prüzen", null], - ["130725255044", "Gutow", null], - ["130725255055", "Klein Upahl", null], - ["130725255061", "Kuhs", null], - ["130725255067", "Lohmen", null], - ["130725255069", "Lüssow", null], - ["130725255071", "Mistorf", null], - ["130725255073", "Mühl Rosin", null], - ["130725255079", "Plaaz", null], - ["130725255084", "Reimershagen", null], - ["130725255092", "Sarmstorf", null], - ["130725255119", "Zehna", null], - ["130725256026", "Dobbin-Linstow", null], - ["130725256048", "Hoppenrade", null], - ["130725256056", "Krakow am See, Stadt", null], - ["130725256059", "Kuchelmiß", null], - ["130725256063", "Lalendorf", null], - ["130725257027", "Dolgen am See", null], - ["130725257046", "Hohen Sprenz", null], - ["130725257062", "Laage, Stadt", null], - ["130725257112", "Wardow", null], - ["130725258003", "Alt Sührkow", null], - ["130725258023", "Dahmen", null], - ["130725258024", "Dalkendorf", null], - ["130725258038", "Groß Roge", null], - ["130725258040", "Groß Wokern", null], - ["130725258041", "Groß Wüstenfelde", null], - ["130725258045", "Hohen Demzin", null], - ["130725258049", "Jördenstorf", null], - ["130725258066", "Lelkendorf", null], - ["130725258082", "Prebberede", null], - ["130725258094", "Schorssow", null], - ["130725258096", "Schwasdorf", null], - ["130725258103", "Sukow-Levitzow", null], - ["130725258109", "Thürkow", null], - ["130725258113", "Warnkenhagen", null], - ["130725259002", "Alt Bukow", null], - ["130725259005", "Am Salzhaff", null], - ["130725259008", "Bastorf", null], - ["130725259014", "Biendorf", null], - ["130725259022", "Carinerland", null], - ["130725259085", "Rerik, Ostseebad, Stadt", null], - ["130725260012", "Bentwisch", null], - ["130725260015", "Blankenhagen", null], - ["130725260032", "Gelbensande", null], - ["130725260072", "Mönchhagen", null], - ["130725260088", "Rövershagen", null], - ["130725261011", "Benitz", null], - ["130725261018", "Bröbberow", null], - ["130725261051", "Kassow", null], - ["130725261090", "Rukieten", null], - ["130725261095", "Schwaan, Stadt", null], - ["130725261110", "Vorbeck", null], - ["130725261116", "Wiendorf", null], - ["130725262021", "Cammin", null], - ["130725262034", "Gnewitz", null], - ["130725262037", "Grammow", null], - ["130725262076", "Nustrow", null], - ["130725262097", "Selpin", null], - ["130725262102", "Stubbendorf", null], - ["130725262105", "Tessin, Stadt", null], - ["130725262107", "Thelkow", null], - ["130725262118", "Zarnewanz", null], - ["130725263030", "Elmenhorst/Lichtenhagen", null], - ["130725263057", "Kritzmow", null], - ["130725263064", "Lambrechtshagen", null], - ["130725263077", "Papendorf", null], - ["130725263080", "Pölchow", null], - ["130725263098", "Stäbelow", null], - ["130725263121", "Ziesendorf", null], - ["130730011011", "Binz, Ostseebad", null], - ["130730035035", "Grimmen, Stadt", null], - ["130730055055", "Marlow, Stadt", null], - ["130730070070", "Putbus, Stadt", null], - ["130730080080", "Sassnitz, Stadt", null], - ["130730088088", "Stralsund, Hansestadt", null], - ["130730089089", "Süderholz", null], - ["130730105105", "Zingst, Ostseeheilbad", null], - ["130735351005", "Altenpleen", null], - ["130735351037", "Groß Mohrdorf", null], - ["130735351044", "Klausdorf", null], - ["130735351046", "Kramerhof", null], - ["130735351066", "Preetz", null], - ["130735351068", "Prohn", null], - ["130735352009", "Barth, Stadt", null], - ["130735352018", "Divitz-Spoldershagen", null], - ["130735352025", "Fuhlendorf", null], - ["130735352042", "Karnin", null], - ["130735352043", "Kenz-Küstrow", null], - ["130735352051", "Löbnitz", null], - ["130735352053", "Lüdershagen", null], - ["130735352069", "Pruchten", null], - ["130735352077", "Saal", null], - ["130735352094", "Trinwillershagen", null], - ["130735353010", "Bergen auf Rügen, Stadt", null], - ["130735353014", "Buschvitz", null], - ["130735353027", "Garz/Rügen, Stadt", null], - ["130735353038", "Gustow", null], - ["130735353049", "Lietzow", null], - ["130735353063", "Parchtitz", null], - ["130735353064", "Patzig", null], - ["130735353065", "Poseritz", null], - ["130735353072", "Ralswiek", null], - ["130735353074", "Rappin", null], - ["130735353083", "Sehlen", null], - ["130735354002", "Ahrenshoop, Ostseebad", null], - ["130735354012", "Born a. Darß", null], - ["130735354017", "Dierhagen, Ostseebad", null], - ["130735354067", "Prerow, Ostseebad", null], - ["130735354100", "Wieck a. Darß", null], - ["130735354103", "Wustrow, Ostseebad", null], - ["130735355024", "Franzburg, Stadt", null], - ["130735355029", "Glewitz", null], - ["130735355034", "Gremersdorf-Buchholz", null], - ["130735355057", "Millienhagen-Oebelitz", null], - ["130735355062", "Papenhagen", null], - ["130735355076", "Richtenberg, Stadt", null], - ["130735355086", "Splietsdorf", null], - ["130735355096", "Velgast", null], - ["130735355097", "Weitenhagen", null], - ["130735355098", "Wendisch Baggendorf", null], - ["130735356023", "Elmenhorst", null], - ["130735356090", "Sundhagen", null], - ["130735356102", "Wittenhagen", null], - ["130735357006", "Baabe, Ostseebad", null], - ["130735357031", "Göhren, Ostseebad", null], - ["130735357048", "Lancken-Granitz", null], - ["130735357084", "Sellin, Ostseebad", null], - ["130735357106", "Zirkow", null], - ["130735357107", "Mönchgut, Ostseebad", null], - ["130735358036", "Groß Kordshagen", null], - ["130735358041", "Jakobsdorf", null], - ["130735358054", "Lüssow", null], - ["130735358060", "Niepars", null], - ["130735358061", "Pantelitz", null], - ["130735358087", "Steinhagen", null], - ["130735358099", "Wendorf", null], - ["130735358104", "Zarrendorf", null], - ["130735359004", "Altenkirchen", null], - ["130735359013", "Breege", null], - ["130735359019", "Dranske", null], - ["130735359030", "Glowe", null], - ["130735359052", "Lohme", null], - ["130735359071", "Putgarten", null], - ["130735359078", "Sagard", null], - ["130735359101", "Wiek", null], - ["130735360007", "Bad Sülze, Stadt", null], - ["130735360015", "Dettmannsdorf", null], - ["130735360016", "Deyelsdorf", null], - ["130735360020", "Drechow", null], - ["130735360022", "Eixen", null], - ["130735360032", "Grammendorf", null], - ["130735360033", "Gransebieth", null], - ["130735360039", "Hugoldsdorf", null], - ["130735360050", "Lindholz", null], - ["130735360093", "Tribsees, Stadt", null], - ["130735361001", "Ahrenshagen-Daskow", null], - ["130735361075", "Ribnitz-Damgarten, Bernsteinstadt", null], - ["130735361082", "Schlemmin", null], - ["130735361085", "Semlow", null], - ["130735362003", "Altefähr", null], - ["130735362021", "Dreschvitz", null], - ["130735362028", "Gingst", null], - ["130735362040", "Insel Hiddensee, Seebad", null], - ["130735362045", "Kluis", null], - ["130735362059", "Neuenkirchen", null], - ["130735362073", "Rambin", null], - ["130735362079", "Samtens", null], - ["130735362081", "Schaprode", null], - ["130735362092", "Trent", null], - ["130735362095", "Ummanz", null], - ["130740026026", "Grevesmühlen, Stadt", null], - ["130740035035", "Insel Poel, Ostseebad", null], - ["130740087087", "Wismar, Hansestadt", null], - ["130745451002", "Bad Kleinen", null], - ["130745451003", "Barnekow", null], - ["130745451008", "Bobitz", null], - ["130745451019", "Dorf Mecklenburg", null], - ["130745451030", "Groß Stieten", null], - ["130745451031", "Hohen Viecheln", null], - ["130745451047", "Lübow", null], - ["130745451053", "Metelsdorf", null], - ["130745451082", "Ventschow", null], - ["130745452020", "Dragun", null], - ["130745452021", "Gadebusch, Stadt", null], - ["130745452040", "Kneese", null], - ["130745452043", "Krembz", null], - ["130745452054", "Mühlen Eichsen", null], - ["130745452068", "Roggendorf", null], - ["130745452070", "Rögnitz", null], - ["130745452081", "Veelböken", null], - ["130745453005", "Bernstorf", null], - ["130745453022", "Gägelow", null], - ["130745453069", "Roggenstorf", null], - ["130745453071", "Rüting", null], - ["130745453077", "Testorf-Steinfort", null], - ["130745453079", "Upahl", null], - ["130745453085", "Warnow", null], - ["130745453093", "Stepenitztal", null], - ["130745454010", "Boltenhagen, Ostseebad", null], - ["130745454016", "Damshagen", null], - ["130745454032", "Hohenkirchen", null], - ["130745454037", "Kalkhorst", null], - ["130745454039", "Klütz, Stadt", null], - ["130745454089", "Zierow", null], - ["130745455001", "Alt Meteln", null], - ["130745455012", "Brüsewitz", null], - ["130745455014", "Cramonshagen", null], - ["130745455015", "Dalberg-Wendelstorf", null], - ["130745455024", "Gottesgabe", null], - ["130745455025", "Grambow", null], - ["130745455038", "Klein Trebbow", null], - ["130745455048", "Lübstorf", null], - ["130745455050", "Lützow", null], - ["130745455061", "Perlin", null], - ["130745455062", "Pingelshagen", null], - ["130745455064", "Pokrent", null], - ["130745455072", "Schildetal", null], - ["130745455075", "Seehof", null], - ["130745455088", "Zickhusen", null], - ["130745456004", "Benz", null], - ["130745456007", "Blowatz", null], - ["130745456009", "Boiensdorf", null], - ["130745456034", "Hornstorf", null], - ["130745456044", "Krusenhagen", null], - ["130745456056", "Neuburg", null], - ["130745457006", "Bibow", null], - ["130745457023", "Glasin", null], - ["130745457036", "Jesendorf", null], - ["130745457046", "Lübberstorf", null], - ["130745457057", "Neukloster, Stadt", null], - ["130745457060", "Passee", null], - ["130745457084", "Warin, Stadt", null], - ["130745457090", "Zurow", null], - ["130745457091", "Züsow", null], - ["130745458013", "Carlow", null], - ["130745458018", "Dechow", null], - ["130745458028", "Groß Molzahn", null], - ["130745458033", "Holdorf", null], - ["130745458042", "Königsfeld", null], - ["130745458065", "Rehna, Stadt", null], - ["130745458066", "Rieps", null], - ["130745458073", "Schlagsdorf", null], - ["130745458078", "Thandorf", null], - ["130745458080", "Utecht", null], - ["130745458092", "Wedendorfersee", null], - ["130745459017", "Dassow, Stadt", null], - ["130745459027", "Grieben", null], - ["130745459049", "Lüdersdorf", null], - ["130745459052", "Menzendorf", null], - ["130745459067", "Roduchelstorf", null], - ["130745459074", "Schönberg, Stadt", null], - ["130745459076", "Selmsdorf", null], - ["130745459094", "Siemz-Niendorf", null], - ["130750005005", "Anklam, Hansestadt", null], - ["130750039039", "Greifswald, Universitäts- und Hansestadt", null], - ["130750049049", "Heringsdorf, Ostseebad", null], - ["130750105105", "Pasewalk, Stadt", null], - ["130750130130", "Strasburg (Uckermark), Stadt", null], - ["130750136136", "Ueckermünde, Seebad , Stadt", null], - ["130755551021", "Buggenhagen", null], - ["130755551072", "Krummin", null], - ["130755551074", "Lassan, Stadt", null], - ["130755551087", "Lütow", null], - ["130755551124", "Sauzin", null], - ["130755551144", "Wolgast, Stadt", null], - ["130755551147", "Zemitz", null], - ["130755552001", "Ahlbeck", null], - ["130755552003", "Altwarp", null], - ["130755552031", "Eggesin, Stadt", null], - ["130755552037", "Grambin", null], - ["130755552051", "Hintersee", null], - ["130755552075", "Leopoldshagen", null], - ["130755552078", "Liepgarten", null], - ["130755552084", "Lübs", null], - ["130755552085", "Luckow", null], - ["130755552089", "Meiersberg", null], - ["130755552093", "Mönkebude", null], - ["130755552139", "Vogelsang-Warsin", null], - ["130755553007", "Bargischow", null], - ["130755553013", "Blesewitz", null], - ["130755553015", "Boldekow", null], - ["130755553020", "Bugewitz", null], - ["130755553022", "Butzow", null], - ["130755553029", "Ducherow", null], - ["130755553053", "Iven", null], - ["130755553068", "Krien", null], - ["130755553073", "Krusenfelde", null], - ["130755553088", "Medow", null], - ["130755553098", "Neu Kosenow", null], - ["130755553101", "Neuenkirchen", null], - ["130755553110", "Postlow", null], - ["130755553116", "Rossin", null], - ["130755553122", "Sarnow", null], - ["130755553127", "Spantekow", null], - ["130755553128", "Stolpe an der Peene", null], - ["130755553155", "Neetzow-Liepen", null], - ["130755554002", "Alt Tellin", null], - ["130755554009", "Bentzin", null], - ["130755554023", "Daberkow", null], - ["130755554054", "Jarmen, Stadt", null], - ["130755554070", "Kruckow", null], - ["130755554134", "Tutow", null], - ["130755554140", "Völschow", null], - ["130755555008", "Behrenhoff", null], - ["130755555025", "Dargelin", null], - ["130755555027", "Dersekow", null], - ["130755555050", "Hinrichshagen", null], - ["130755555076", "Levenhagen", null], - ["130755555091", "Mesekenhagen", null], - ["130755555102", "Neuenkirchen", null], - ["130755555141", "Wackerow", null], - ["130755555142", "Weitenhagen", null], - ["130755556011", "Bergholz", null], - ["130755556012", "Blankensee", null], - ["130755556016", "Boock", null], - ["130755556035", "Glasow", null], - ["130755556038", "Grambow", null], - ["130755556067", "Krackow", null], - ["130755556079", "Löcknitz", null], - ["130755556095", "Nadrensee", null], - ["130755556107", "Penkun, Stadt", null], - ["130755556108", "Plöwen", null], - ["130755556113", "Ramin", null], - ["130755556117", "Rossow", null], - ["130755556119", "Rothenklempenow", null], - ["130755557018", "Brünzow", null], - ["130755557046", "Hanshagen", null], - ["130755557059", "Katzow", null], - ["130755557060", "Kemnitz", null], - ["130755557069", "Kröslin", null], - ["130755557081", "Loissin", null], - ["130755557083", "Lubmin, Seebad", null], - ["130755557097", "Neu Boltenhagen", null], - ["130755557120", "Rubenow", null], - ["130755557146", "Wusterhusen", null], - ["130755558036", "Görmin", null], - ["130755558082", "Loitz, Stadt", null], - ["130755558123", "Sassen-Trantow", null], - ["130755559004", "Altwigshagen", null], - ["130755559033", "Ferdinandshof", null], - ["130755559045", "Hammer a.d. Uecker", null], - ["130755559048", "Heinrichswalde", null], - ["130755559118", "Rothemühl", null], - ["130755559131", "Torgelow, Stadt", null], - ["130755559143", "Wilhelmsburg", null], - ["130755560017", "Brietzig", null], - ["130755560032", "Fahrenwalde", null], - ["130755560042", "Groß Luckow", null], - ["130755560055", "Jatznick", null], - ["130755560063", "Koblentz", null], - ["130755560071", "Krugsdorf", null], - ["130755560103", "Nieden", null], - ["130755560104", "Papendorf", null], - ["130755560109", "Polzow", null], - ["130755560115", "Rollwitz", null], - ["130755560126", "Schönwalde", null], - ["130755560138", "Viereck", null], - ["130755560149", "Zerrenthin", null], - ["130755561058", "Karlshagen, Ostseebad", null], - ["130755561092", "Mölschow", null], - ["130755561106", "Peenemünde", null], - ["130755561133", "Trassenheide, Ostseebad", null], - ["130755561151", "Zinnowitz, Ostseebad", null], - ["130755562010", "Benz", null], - ["130755562026", "Dargen", null], - ["130755562034", "Garz", null], - ["130755562056", "Kamminke", null], - ["130755562065", "Korswandt", null], - ["130755562066", "Koserow, Ostseebad", null], - ["130755562080", "Loddin, Seebad", null], - ["130755562090", "Mellenthin", null], - ["130755562111", "Pudagla", null], - ["130755562114", "Rankwitz", null], - ["130755562129", "Stolpe auf Usedom", null], - ["130755562135", "Ückeritz, Seebad", null], - ["130755562137", "Usedom, Stadt", null], - ["130755562148", "Zempin, Seebad", null], - ["130755562152", "Zirchow", null], - ["130755563006", "Bandelin", null], - ["130755563040", "Gribow", null], - ["130755563041", "Groß Kiesow", null], - ["130755563043", "Groß Polzin", null], - ["130755563044", "Gützkow, Stadt", null], - ["130755563061", "Klein Bünzow", null], - ["130755563094", "Murchin", null], - ["130755563121", "Rubkow", null], - ["130755563125", "Schmatzin", null], - ["130755563145", "Wrangelsburg", null], - ["130755563150", "Ziethen", null], - ["130755563154", "Züssow", null], - ["130755563156", "Karlsburg", null], - ["130760014014", "Boizenburg/ Elbe, Stadt", null], - ["130760060060", "Hagenow, Stadt", null], - ["130760088088", "Lübtheen, Stadt", null], - ["130760090090", "Ludwigslust, Stadt", null], - ["130760108108", "Parchim, Stadt", null], - ["130765652009", "Bengerstorf", null], - ["130765652010", "Besitz", null], - ["130765652016", "Brahlstorf", null], - ["130765652030", "Dersenow", null], - ["130765652054", "Gresse", null], - ["130765652055", "Greven", null], - ["130765652102", "Neu Gülze", null], - ["130765652106", "Nostorf", null], - ["130765652122", "Schwanheide", null], - ["130765652136", "Teldau", null], - ["130765652138", "Tessin b. Boizenburg", null], - ["130765654034", "Dömitz, Stadt", null], - ["130765654053", "Grebs-Niendorf", null], - ["130765654067", "Karenz", null], - ["130765654093", "Malk Göhren", null], - ["130765654094", "Malliß", null], - ["130765654103", "Neu Kaliß", null], - ["130765654143", "Vielank", null], - ["130765655040", "Gallin-Kuppentin", null], - ["130765655051", "Granzin", null], - ["130765655075", "Kreien", null], - ["130765655077", "Kritzow", null], - ["130765655089", "Lübz, Stadt", null], - ["130765655109", "Passow", null], - ["130765655125", "Siggelkow", null], - ["130765655151", "Werder", null], - ["130765655165", "Gehlsbach", null], - ["130765655168", "Ruhner Berge", null], - ["130765656032", "Dobbertin", null], - ["130765656048", "Goldberg, Stadt", null], - ["130765656096", "Mestlin", null], - ["130765656104", "Neu Poserin", null], - ["130765656135", "Techentin", null], - ["130765657003", "Balow", null], - ["130765657021", "Brunow", null], - ["130765657027", "Dambeck", null], - ["130765657037", "Eldena", null], - ["130765657049", "Gorlosen", null], - ["130765657050", "Grabow, Stadt", null], - ["130765657069", "Karstädt", null], - ["130765657076", "Kremmin", null], - ["130765657097", "Milow", null], - ["130765657098", "Möllenbeck", null], - ["130765657100", "Muchow", null], - ["130765657115", "Prislich", null], - ["130765657161", "Zierzow", null], - ["130765658002", "Alt Zachun", null], - ["130765658004", "Bandenitz", null], - ["130765658008", "Belsch", null], - ["130765658013", "Bobzin", null], - ["130765658019", "Bresegard bei Picher", null], - ["130765658041", "Gammelin", null], - ["130765658057", "Groß Krams", null], - ["130765658064", "Hoort", null], - ["130765658065", "Hülseburg", null], - ["130765658070", "Kirch Jesar", null], - ["130765658079", "Kuhstorf", null], - ["130765658099", "Moraas", null], - ["130765658110", "Pätow-Steegen", null], - ["130765658111", "Picher", null], - ["130765658116", "Pritzier", null], - ["130765658119", "Redefin", null], - ["130765658131", "Strohkirchen", null], - ["130765658169", "Toddin", null], - ["130765658145", "Warlitz", null], - ["130765659001", "Alt Krenzlin", null], - ["130765659018", "Bresegard bei Eldena", null], - ["130765659046", "Göhlen", null], - ["130765659058", "Groß Laasch", null], - ["130765659086", "Lübesse", null], - ["130765659087", "Lüblow", null], - ["130765659118", "Rastow", null], - ["130765659134", "Sülstorf", null], - ["130765659141", "Uelitz", null], - ["130765659146", "Warlow", null], - ["130765659156", "Wöbbelin", null], - ["130765660012", "Blievenstorf", null], - ["130765660017", "Brenz", null], - ["130765660105", "Neustadt-Glewe, Stadt", null], - ["130765662035", "Domsühl", null], - ["130765662056", "Groß Godems", null], - ["130765662068", "Karrenzin", null], - ["130765662085", "Lewitzrand", null], - ["130765662120", "Rom", null], - ["130765662126", "Spornitz", null], - ["130765662129", "Stolpe", null], - ["130765662160", "Ziegendorf", null], - ["130765662162", "Zölkow", null], - ["130765662164", "Obere Warnow", null], - ["130765663006", "Barkhagen", null], - ["130765663114", "Plau am See, Stadt", null], - ["130765663166", "Ganzlin", null], - ["130765664011", "Blankenberg", null], - ["130765664015", "Borkow", null], - ["130765664020", "Brüel, Stadt", null], - ["130765664026", "Dabel", null], - ["130765664062", "Hohen Pritz", null], - ["130765664072", "Kobrow", null], - ["130765664078", "Kuhlen-Wendorf", null], - ["130765664101", "Mustin", null], - ["130765664128", "Sternberg, Stadt", null], - ["130765664148", "Weitendorf", null], - ["130765664155", "Witzin", null], - ["130765664167", "Kloster Tempzin", null], - ["130765665036", "Dümmer", null], - ["130765665063", "Holthusen", null], - ["130765665071", "Klein Rogahn", null], - ["130765665107", "Pampow", null], - ["130765665121", "Schossin", null], - ["130765665130", "Stralendorf", null], - ["130765665147", "Warsow", null], - ["130765665154", "Wittenförden", null], - ["130765665163", "Zülow", null], - ["130765666152", "Wittenburg, Stadt", null], - ["130765666153", "Wittendörp", null], - ["130765667039", "Gallin", null], - ["130765667073", "Kogel", null], - ["130765667092", "Lüttow-Valluhn", null], - ["130765667142", "Vellahn", null], - ["130765667159", "Zarrentin am Schaalsee, Stadt", null], - ["130765668005", "Banzkow", null], - ["130765668007", "Barnin", null], - ["130765668023", "Bülow", null], - ["130765668024", "Cambs", null], - ["130765668025", "Crivitz, Stadt", null], - ["130765668029", "Demen", null], - ["130765668033", "Dobin am See", null], - ["130765668038", "Friedrichsruhe", null], - ["130765668044", "Gneven", null], - ["130765668080", "Langen Brütz", null], - ["130765668082", "Leezen", null], - ["130765668112", "Pinnow", null], - ["130765668113", "Plate", null], - ["130765668117", "Raben Steinfeld", null], - ["130765668133", "Sukow", null], - ["130765668140", "Tramm", null], - ["130765668158", "Zapel", null], - ["145110000000", "Chemnitz, Stadt", null], - ["145210010010", "Amtsberg", null], - ["145210020020", "Annaberg-Buchholz, Stadt", null], - ["145210035035", "Aue-Bad Schlema, Stadt", null], - ["145210110110", "Breitenbrunn/Erzgeb.", null], - ["145210130130", "Crottendorf", null], - ["145210150150", "Drebach", null], - ["145210160160", "Ehrenfriedersdorf, Stadt", null], - ["145210170170", "Eibenstock, Stadt", null], - ["145210200200", "Gelenau/Erzgeb.", null], - ["145210240240", "Großolbersdorf", null], - ["145210250250", "Großrückerswalde", null], - ["145210260260", "Grünhain-Beierfeld, Stadt", null], - ["145210290290", "Hohndorf", null], - ["145210310310", "Jahnsdorf/Erzgeb.", null], - ["145210320320", "Johanngeorgenstadt, Stadt", null], - ["145210330330", "Jöhstadt, Stadt", null], - ["145210355355", "Lauter-Bernsbach, Stadt", null], - ["145210370370", "Lößnitz, Stadt", null], - ["145210390390", "Marienberg, Stadt", null], - ["145210400400", "Mildenau", null], - ["145210410410", "Neukirchen/Erzgeb.", null], - ["145210440440", "Oberwiesenthal, Kurort, Stadt", null], - ["145210450450", "Oelsnitz/Erzgeb., Stadt", null], - ["145210460460", "Olbernhau, Stadt", null], - ["145210495495", "Pockau-Lengefeld, Stadt", null], - ["145210500500", "Raschau-Markersbach", null], - ["145210530530", "Schneeberg, Stadt", null], - ["145210540540", "Schönheide", null], - ["145210550550", "Schwarzenberg/Erzgeb., Stadt", null], - ["145210560560", "Sehmatal", null], - ["145210600600", "Stützengrün", null], - ["145210620620", "Thalheim/Erzgeb., Stadt", null], - ["145210630630", "Thermalbad Wiesenbad", null], - ["145210640640", "Thum, Stadt", null], - ["145210670670", "Wolkenstein, Stadt", null], - ["145215101060", "Bärenstein", null], - ["145215101340", "Königswalde", null], - ["145215103040", "Auerbach", null], - ["145215103120", "Burkhardtsdorf", null], - ["145215103230", "Gornsdorf", null], - ["145215110210", "Geyer, Stadt", null], - ["145215110610", "Tannenberg", null], - ["145215115380", "Lugau/Erzgeb., Stadt", null], - ["145215115430", "Niederwürschnitz", null], - ["145215130510", "Scheibenberg, Stadt", null], - ["145215130520", "Schlettau, Stadt", null], - ["145215132140", "Deutschneudorf", null], - ["145215132280", "Heidersdorf", null], - ["145215132570", "Seiffen/Erzgeb., Kurort", null], - ["145215133420", "Niederdorf", null], - ["145215133590", "Stollberg/Erzgeb., Stadt", null], - ["145215138220", "Gornau/Erzgeb.", null], - ["145215138690", "Zschopau, Stadt", null], - ["145215139080", "Bockau", null], - ["145215139700", "Zschorlau", null], - ["145215140180", "Elterlein, Stadt", null], - ["145215140710", "Zwönitz, Stadt", null], - ["145215405090", "Börnichen/Erzgeb.", null], - ["145215405270", "Grünhainichen", null], - ["145220020020", "Augustusburg, Stadt", null], - ["145220035035", "Bobritzsch-Hilbersdorf", null], - ["145220050050", "Brand-Erbisdorf, Stadt", null], - ["145220070070", "Claußnitz", null], - ["145220080080", "Döbeln, Stadt", null], - ["145220110110", "Eppendorf", null], - ["145220120120", "Erlau", null], - ["145220140140", "Flöha, Stadt", null], - ["145220150150", "Frankenberg/Sa., Stadt", null], - ["145220170170", "Frauenstein, Stadt", null], - ["145220180180", "Freiberg, Stadt, Universitätsstadt", null], - ["145220190190", "Geringswalde, Stadt", null], - ["145220200200", "Großhartmannsdorf", null], - ["145220210210", "Großschirma, Stadt", null], - ["145220220220", "Großweitzschen", null], - ["145220230230", "Hainichen, Stadt", null], - ["145220240240", "Halsbrücke", null], - ["145220250250", "Hartha, Stadt", null], - ["145220260260", "Hartmannsdorf", null], - ["145220290290", "Königshain-Wiederau", null], - ["145220300300", "Kriebstein", null], - ["145220310310", "Leisnig, Stadt", null], - ["145220320320", "Leubsdorf", null], - ["145220330330", "Lichtenau", null], - ["145220350350", "Lunzenau, Stadt", null], - ["145220390390", "Mulda/Sa.", null], - ["145220400400", "Neuhausen/Erzgeb.", null], - ["145220420420", "Niederwiesa", null], - ["145220430430", "Oberschöna", null], - ["145220440440", "Oederan, Stadt", null], - ["145220460460", "Penig, Stadt", null], - ["145220470470", "Rechenberg-Bienenmühle", null], - ["145220480480", "Reinsberg", null], - ["145220500500", "Rossau", null], - ["145220510510", "Roßwein, Stadt", null], - ["145220540540", "Striegistal", null], - ["145220570570", "Waldheim, Stadt", null], - ["145220580580", "Wechselburg", null], - ["145225102060", "Burgstädt, Stadt", null], - ["145225102380", "Mühlau", null], - ["145225102550", "Taura", null], - ["145225113340", "Lichtenberg/Erzgeb.", null], - ["145225113590", "Weißenborn/Erzgeb.", null], - ["145225119010", "Altmittweida", null], - ["145225119360", "Mittweida, Stadt, Hochschulstadt", null], - ["145225123450", "Ostrau", null], - ["145225123620", "Zschaitz-Ottewig", null], - ["145225126280", "Königsfeld", null], - ["145225126490", "Rochlitz, Stadt", null], - ["145225126530", "Seelitz", null], - ["145225126600", "Zettlitz", null], - ["145225129090", "Dorfchemnitz", null], - ["145225129520", "Sayda, Stadt", null], - ["145230010010", "Adorf/Vogtl., Stadt", null], - ["145230020020", "Auerbach/Vogtl., Stadt", null], - ["145230030030", "Bad Brambach", null], - ["145230040040", "Bad Elster, Stadt", null], - ["145230090090", "Ellefeld", null], - ["145230100100", "Elsterberg, Stadt", null], - ["145230160160", "Klingenthal, Stadt", null], - ["145230170170", "Lengenfeld, Stadt", null], - ["145230200200", "Markneukirchen, Stadt", null], - ["145230245245", "Muldenhammer", null], - ["145230280280", "Neumark", null], - ["145230310310", "Pausa-Mühltroff, Stadt", null], - ["145230320320", "Plauen, Stadt", null], - ["145230330330", "Pöhl", null], - ["145230360360", "Rodewisch, Stadt", null], - ["145230365365", "Rosenbach/Vogtl.", null], - ["145230380380", "Steinberg", null], - ["145230450450", "Weischlitz", null], - ["145235107120", "Falkenstein/Vogtl., Stadt", null], - ["145235107130", "Grünbach", null], - ["145235107290", "Neustadt/Vogtl.", null], - ["145235120190", "Limbach", null], - ["145235120260", "Netzschkau, Stadt", null], - ["145235122060", "Bösenbrunn", null], - ["145235122080", "Eichigt", null], - ["145235122300", "Oelsnitz/Vogtl., Stadt", null], - ["145235122440", "Triebel/Vogtl.", null], - ["145235125150", "Heinsdorfergrund", null], - ["145235125340", "Reichenbach im Vogtland, Stadt", null], - ["145235131230", "Mühlental", null], - ["145235131370", "Schöneck/Vogtl., Stadt", null], - ["145235134270", "Neuensalz", null], - ["145235134430", "Treuen, Stadt", null], - ["145235402050", "Bergen", null], - ["145235402410", "Theuma", null], - ["145235402420", "Tirpersdorf", null], - ["145235402460", "Werda", null], - ["145240020020", "Callenberg", null], - ["145240060060", "Fraureuth", null], - ["145240070070", "Gersdorf", null], - ["145240080080", "Glauchau, Stadt", null], - ["145240090090", "Hartenstein, Stadt", null], - ["145240120120", "Hohenstein-Ernstthal, Stadt", null], - ["145240140140", "Langenbernsdorf", null], - ["145240150150", "Langenweißbach", null], - ["145240170170", "Lichtentanne", null], - ["145240200200", "Mülsen", null], - ["145240210210", "Neukirchen/Pleiße", null], - ["145240230230", "Oberlungwitz, Stadt", null], - ["145240250250", "Reinsdorf", null], - ["145240300300", "Werdau, Stadt", null], - ["145240310310", "Wildenfels, Stadt", null], - ["145240320320", "Wilkau-Haßlau, Stadt", null], - ["145240330330", "Zwickau, Stadt", null], - ["145245104030", "Crimmitschau, Stadt", null], - ["145245104050", "Dennheritz", null], - ["145245111040", "Crinitzberg", null], - ["145245111100", "Hartmannsdorf b. Kirchberg", null], - ["145245111110", "Hirschfeld", null], - ["145245111130", "Kirchberg, Stadt", null], - ["145245114180", "Limbach-Oberfrohna, Stadt", null], - ["145245114220", "Niederfrohna", null], - ["145245118190", "Meerane, Stadt", null], - ["145245118270", "Schönberg", null], - ["145245128010", "Bernsdorf", null], - ["145245128160", "Lichtenstein/Sa., Stadt", null], - ["145245128280", "St. Egidien", null], - ["145245135240", "Oberwiera", null], - ["145245135260", "Remse", null], - ["145245135290", "Waldenburg, Stadt", null], - ["146120000000", "Dresden, Stadt", null], - ["146250010010", "Arnsdorf", null], - ["146250020020", "Bautzen / Budyšin, Stadt", null], - ["146250030030", "Bernsdorf, Stadt", null], - ["146250060060", "Burkau", null], - ["146250090090", "Cunewalde", null], - ["146250100100", "Demitz-Thumitz", null], - ["146250110110", "Doberschau-Gaußig / Dobruša-Huska", null], - ["146250120120", "Elsterheide / Halštrowska Hola", null], - ["146250130130", "Elstra, Stadt", null], - ["146250150150", "Göda / Hodźij", null], - ["146250160160", "Großdubrau / Wulka Dubrawa", null], - ["146250200200", "Großröhrsdorf, Stadt", null], - ["146250220220", "Haselbachtal", null], - ["146250230230", "Hochkirch / Bukecy", null], - ["146250240240", "Hoyerswerda / Wojerecy, Stadt", null], - ["146250250250", "Kamenz / Kamjenc, Stadt", null], - ["146250280280", "Königswartha / Rakecy", null], - ["146250290290", "Kubschütz / Kubšicy", null], - ["146250310310", "Lauta, Stadt", null], - ["146250330330", "Lohsa / Łaz", null], - ["146250340340", "Malschwitz / Malešecy", null], - ["146250380380", "Neukirch/Lausitz", null], - ["146250420420", "Oßling", null], - ["146250430430", "Ottendorf-Okrilla", null], - ["146250480480", "Radeberg, Stadt", null], - ["146250490490", "Radibor / Radwor", null], - ["146250525525", "Schirgiswalde-Kirschau, Stadt", null], - ["146250530530", "Schmölln-Putzkau", null], - ["146250550550", "Schwepnitz", null], - ["146250560560", "Sohland a. d. Spree", null], - ["146250570570", "Spreetal / Sprjewiny Doł", null], - ["146250590590", "Steinigtwolmsdorf", null], - ["146250600600", "Wachau", null], - ["146250610610", "Weißenberg / Wóspork, Stadt", null], - ["146250630630", "Wilthen, Stadt", null], - ["146250640640", "Wittichenau / Kulow, Stadt", null], - ["146255207040", "Bischofswerda, Stadt", null], - ["146255207510", "Rammenau", null], - ["146255211140", "Frankenthal", null], - ["146255211170", "Großharthau", null], - ["146255212190", "Großpostwitz/O.L. / Budestecy", null], - ["146255212390", "Obergurig / Hornja Hórka", null], - ["146255218270", "Königsbrück, Stadt", null], - ["146255218300", "Laußnitz", null], - ["146255218370", "Neukirch", null], - ["146255223360", "Neschwitz / Njeswačidło", null], - ["146255223460", "Puschwitz / Bóšicy", null], - ["146255231180", "Großnaundorf", null], - ["146255231320", "Lichtenberg", null], - ["146255231410", "Ohorn", null], - ["146255231450", "Pulsnitz, Stadt", null], - ["146255231580", "Steina", null], - ["146255501080", "Crostwitz / Chrósćicy", null], - ["146255501350", "Nebelschütz / Njebjelčicy", null], - ["146255501440", "Panschwitz-Kuckau / Pančicy-Kukow", null], - ["146255501470", "Räckelwitz / Worklecy", null], - ["146255501500", "Ralbitz-Rosenthal / Ralbicy-Róžant", null], - ["146260060060", "Boxberg/O.L. / Hamor", null], - ["146260085085", "Ebersbach-Neugersdorf, Stadt", null], - ["146260110110", "Görlitz, Stadt", null], - ["146260180180", "Herrnhut, Stadt", null], - ["146260245245", "Kottmar", null], - ["146260250250", "Krauschwitz i.d. O.L. / Krušwica", null], - ["146260280280", "Leutersdorf", null], - ["146260300300", "Markersdorf", null], - ["146260310310", "Mittelherwigsdorf", null], - ["146260370370", "Niesky, Stadt", null], - ["146260390390", "Oderwitz", null], - ["146260420420", "Ostritz, Stadt", null], - ["146260530530", "Seifhennersdorf, Stadt", null], - ["146260610610", "Zittau, Stadt", null], - ["146265203010", "Bad Muskau / Mužakow, Stadt", null], - ["146265203100", "Gablenz / Jabłońc", null], - ["146265206030", "Bernstadt a. d. Eigen, Stadt", null], - ["146265206500", "Schönau-Berzdorf a. d. Eigen", null], - ["146265214140", "Großschönau", null], - ["146265214170", "Hainewalde", null], - ["146265220150", "Großschweidnitz", null], - ["146265220270", "Lawalde", null], - ["146265220290", "Löbau, Stadt", null], - ["146265220470", "Rosenbach", null], - ["146265224070", "Dürrhennersdorf", null], - ["146265224350", "Neusalza-Spremberg, Stadt", null], - ["146265224510", "Schönbach", null], - ["146265227050", "Bertsdorf-Hörnitz", null], - ["146265227210", "Jonsdorf, Kurort", null], - ["146265227400", "Olbersdorf", null], - ["146265227430", "Oybin", null], - ["146265228020", "Beiersdorf", null], - ["146265228410", "Oppach", null], - ["146265232240", "Königshain", null], - ["146265232450", "Reichenbach/O.L., Stadt", null], - ["146265232570", "Vierkirchen", null], - ["146265233260", "Kreba-Neudorf / Chrjebja-Nowa Wjes", null], - ["146265233460", "Rietschen / Rěčicy", null], - ["146265235160", "Hähnichen", null], - ["146265235480", "Rothenburg/O.L., Stadt", null], - ["146265237120", "Groß Düben / Dźěwin", null], - ["146265237490", "Schleife / Slepo", null], - ["146265237560", "Trebendorf / Trjebin", null], - ["146265242590", "Weißkeißel / Wuskidź", null], - ["146265242600", "Weißwasser/O.L., Stadt / Běła Woda", null], - ["146265502190", "Hohendubrau / Wysoka Dubrawa", null], - ["146265502320", "Mücka / Mikow", null], - ["146265502440", "Quitzdorf am See", null], - ["146265502580", "Waldhufen", null], - ["146265503200", "Horka", null], - ["146265503230", "Kodersdorf", null], - ["146265503330", "Neißeaue", null], - ["146265503520", "Schöpstal", null], - ["146270010010", "Coswig, Stadt", null], - ["146270020020", "Diera-Zehren", null], - ["146270030030", "Ebersbach", null], - ["146270050050", "Gröditz, Stadt", null], - ["146270060060", "Großenhain, Stadt", null], - ["146270070070", "Hirschstein", null], - ["146270080080", "Käbschütztal", null], - ["146270100100", "Klipphausen", null], - ["146270130130", "Lommatzsch, Stadt", null], - ["146270140140", "Meißen, Stadt", null], - ["146270150150", "Moritzburg", null], - ["146270170170", "Niederau", null], - ["146270180180", "Nossen, Stadt", null], - ["146270200200", "Priestewitz", null], - ["146270210210", "Radebeul, Stadt", null], - ["146270220220", "Radeburg, Stadt", null], - ["146270230230", "Riesa, Stadt", null], - ["146270260260", "Stauchitz", null], - ["146270270270", "Strehla, Stadt", null], - ["146270290290", "Thiendorf", null], - ["146270310310", "Weinböhla", null], - ["146270360360", "Zeithain", null], - ["146275225040", "Glaubitz", null], - ["146275225190", "Nünchritz", null], - ["146275234240", "Röderaue", null], - ["146275234340", "Wülknitz", null], - ["146275238110", "Lampertswalde", null], - ["146275238250", "Schönfeld", null], - ["146280050050", "Bannewitz", null], - ["146280060060", "Dippoldiswalde, Stadt", null], - ["146280100100", "Dürrröhrsdorf-Dittersbach", null], - ["146280110110", "Freital, Stadt", null], - ["146280130130", "Glashütte, Stadt", null], - ["146280160160", "Heidenau, Stadt", null], - ["146280190190", "Hohnstein, Stadt", null], - ["146280220220", "Kreischa", null], - ["146280260260", "Neustadt in Sachsen, Stadt", null], - ["146280300300", "Rabenau, Stadt", null], - ["146280360360", "Sebnitz, Stadt", null], - ["146280380380", "Stolpen, Stadt", null], - ["146280410410", "Wilsdruff, Stadt", null], - ["146285201010", "Altenberg, Stadt", null], - ["146285201170", "Hermsdorf/Erzgeb.", null], - ["146285202020", "Bad Gottleuba-Berggießhübel, Stadt", null], - ["146285202040", "Bahretal", null], - ["146285202230", "Liebstadt, Stadt", null], - ["146285204030", "Bad Schandau, Stadt", null], - ["146285204320", "Rathmannsdorf", null], - ["146285204330", "Reinhardtsdorf-Schöna", null], - ["146285209080", "Dohna, Stadt", null], - ["146285209250", "Müglitztal", null], - ["146285219140", "Gohrisch", null], - ["146285219210", "Königstein/Sächs. Schw., Stadt", null], - ["146285219310", "Rathen, Kurort", null], - ["146285219340", "Rosenthal-Bielatal", null], - ["146285219390", "Struppen", null], - ["146285221240", "Lohmen", null], - ["146285221370", "Stadt Wehlen, Stadt", null], - ["146285229070", "Dohma", null], - ["146285229270", "Pirna, Stadt", null], - ["146285230150", "Hartmannsdorf-Reichenau", null], - ["146285230205", "Klingenberg", null], - ["146285240090", "Dorfhain", null], - ["146285240400", "Tharandt, Stadt", null], - ["147130000000", "Leipzig, Stadt", null], - ["147290030030", "Bennewitz", null], - ["147290040040", "Böhlen, Stadt", null], - ["147290050050", "Borna, Stadt", null], - ["147290060060", "Borsdorf", null], - ["147290070070", "Brandis, Stadt", null], - ["147290080080", "Colditz, Stadt", null], - ["147290140140", "Frohburg, Stadt", null], - ["147290150150", "Geithain, Stadt", null], - ["147290160160", "Grimma, Stadt", null], - ["147290170170", "Groitzsch, Stadt", null], - ["147290190190", "Großpösna", null], - ["147290220220", "Kitzscher, Stadt", null], - ["147290245245", "Lossatal", null], - ["147290250250", "Machern", null], - ["147290260260", "Markkleeberg, Stadt", null], - ["147290270270", "Markranstädt, Stadt", null], - ["147290320320", "Neukieritzsch", null], - ["147290360360", "Regis-Breitingen, Stadt", null], - ["147290370370", "Rötha, Stadt", null], - ["147290380380", "Thallwitz", null], - ["147290400400", "Trebsen/Mulde, Stadt", null], - ["147290410410", "Wurzen, Stadt", null], - ["147290430430", "Zwenkau, Stadt", null], - ["147295301010", "Bad Lausick, Stadt", null], - ["147295301330", "Otterwisch", null], - ["147295307020", "Belgershain", null], - ["147295307300", "Naunhof, Stadt", null], - ["147295307340", "Parthenstein", null], - ["147295308100", "Elstertrebnitz", null], - ["147295308350", "Pegau, Stadt", null], - ["147300020020", "Bad Düben, Stadt", null], - ["147300045045", "Belgern-Schildau, Stadt", null], - ["147300050050", "Cavertitz", null], - ["147300060060", "Dahlen, Stadt", null], - ["147300070070", "Delitzsch, Stadt", null], - ["147300080080", "Doberschütz", null], - ["147300110110", "Eilenburg, Stadt", null], - ["147300160160", "Laußig", null], - ["147300170170", "Liebschützberg", null], - ["147300180180", "Löbnitz", null], - ["147300190190", "Mockrehna", null], - ["147300200200", "Mügeln, Stadt", null], - ["147300210210", "Naundorf", null], - ["147300230230", "Oschatz, Stadt", null], - ["147300250250", "Rackwitz", null], - ["147300270270", "Schkeuditz, Stadt", null], - ["147300300300", "Taucha, Stadt", null], - ["147300330330", "Wermsdorf", null], - ["147300340340", "Wiedemar", null], - ["147305302010", "Arzberg", null], - ["147305302030", "Beilrode", null], - ["147305303090", "Dommitzsch, Stadt", null], - ["147305303120", "Elsnig", null], - ["147305303320", "Trossin", null], - ["147305306150", "Krostitz", null], - ["147305306280", "Schönwölkau", null], - ["147305311100", "Dreiheide", null], - ["147305311310", "Torgau, Stadt", null], - ["147305601140", "Jesewitz", null], - ["147305601360", "Zschepplin", null], - ["150010000000", "Dessau-Roßlau, Stadt", null], - ["150020000000", "Halle (Saale), Stadt", null], - ["150030000000", "Magdeburg, Landeshauptstadt", null], - ["150810030030", "Arendsee (Altmark), Stadt", null], - ["150810135135", "Gardelegen, Hansestadt", null], - ["150810240240", "Kalbe (Milde), Stadt", null], - ["150810280280", "Klötze, Stadt", null], - ["150810455455", "Salzwedel, Hansestadt", null], - ["150815051026", "Apenburg-Winterfeld, Flecken", null], - ["150815051045", "Beetzendorf", null], - ["150815051095", "Dähre", null], - ["150815051105", "Diesdorf, Flecken", null], - ["150815051225", "Jübar", null], - ["150815051290", "Kuhfelde", null], - ["150815051440", "Rohrberg", null], - ["150815051545", "Wallstawe", null], - ["150820005005", "Aken (Elbe), Stadt", null], - ["150820015015", "Bitterfeld-Wolfen, Stadt", null], - ["150820180180", "Köthen (Anhalt), Stadt", null], - ["150820241241", "Muldestausee", null], - ["150820256256", "Osternienburger Land", null], - ["150820301301", "Raguhn-Jeßnitz, Stadt", null], - ["150820340340", "Sandersdorf-Brehna, Stadt", null], - ["150820377377", "Südliches Anhalt, Stadt", null], - ["150820430430", "Zerbst/Anhalt, Stadt", null], - ["150820440440", "Zörbig, Stadt", null], - ["150830040040", "Barleben", null], - ["150830270270", "Haldensleben, Stadt", null], - ["150830298298", "Hohe Börde", null], - ["150830390390", "Niedere Börde", null], - ["150830411411", "Oebisfelde-Weferlingen, Stadt", null], - ["150830415415", "Oschersleben (Bode), Stadt", null], - ["150830490490", "Sülzetal", null], - ["150830531531", "Wanzleben-Börde, Stadt", null], - ["150830565565", "Wolmirstedt, Stadt", null], - ["150835051030", "Angern", null], - ["150835051120", "Burgstall", null], - ["150835051130", "Colbitz", null], - ["150835051361", "Loitsche-Heinrichsberg", null], - ["150835051440", "Rogätz", null], - ["150835051557", "Westheide", null], - ["150835051580", "Zielitz", null], - ["150835052020", "Altenhausen", null], - ["150835052060", "Beendorf", null], - ["150835052115", "Bülstringen", null], - ["150835052125", "Calvörde", null], - ["150835052205", "Erxleben", null], - ["150835052230", "Flechtingen", null], - ["150835052323", "Ingersleben", null], - ["150835053190", "Eilsleben", null], - ["150835053275", "Harbke", null], - ["150835053320", "Hötensleben", null], - ["150835053485", "Sommersdorf", null], - ["150835053505", "Ummendorf", null], - ["150835053515", "Völpke", null], - ["150835053535", "Wefensleben", null], - ["150835054025", "Am Großen Bruch", null], - ["150835054035", "Ausleben", null], - ["150835054245", "Gröningen, Stadt", null], - ["150835054355", "Kroppenstedt, Stadt", null], - ["150840130130", "Elsteraue", null], - ["150840235235", "Hohenmölsen, Stadt", null], - ["150840315315", "Lützen, Stadt", null], - ["150840355355", "Naumburg (Saale), Stadt", null], - ["150840490490", "Teuchern, Stadt", null], - ["150840550550", "Weißenfels, Stadt", null], - ["150840590590", "Zeitz, Stadt", null], - ["150845051012", "An der Poststraße", null], - ["150845051015", "Bad Bibra, Stadt", null], - ["150845051125", "Eckartsberga, Stadt", null], - ["150845051132", "Finne", null], - ["150845051133", "Finneland", null], - ["150845051246", "Kaiserpfalz", null], - ["150845051282", "Lanitz-Hassel-Tal", null], - ["150845052115", "Droyßig", null], - ["150845052207", "Gutenborn", null], - ["150845052275", "Kretzschau", null], - ["150845052442", "Schnaudertal", null], - ["150845052565", "Wetterzeube", null], - ["150845053025", "Balgstädt", null], - ["150845053135", "Freyburg (Unstrut), Stadt", null], - ["150845053150", "Gleina", null], - ["150845053170", "Goseck", null], - ["150845053250", "Karsdorf", null], - ["150845053285", "Laucha an der Unstrut, Stadt", null], - ["150845053360", "Nebra (Unstrut), Stadt", null], - ["150845054013", "Meineweh", null], - ["150845054335", "Mertendorf", null], - ["150845054341", "Molauer Land", null], - ["150845054375", "Osterfeld, Stadt", null], - ["150845054445", "Schönburg", null], - ["150845054470", "Stößen, Stadt", null], - ["150845054560", "Wethau", null], - ["150850040040", "Ballenstedt, Stadt", null], - ["150850055055", "Blankenburg (Harz), Stadt", null], - ["150850110110", "Falkenstein/Harz, Stadt", null], - ["150850135135", "Halberstadt, Stadt", null], - ["150850145145", "Harzgerode, Stadt", null], - ["150850185185", "Huy", null], - ["150850190190", "Ilsenburg (Harz), Stadt", null], - ["150850227227", "Nordharz", null], - ["150850228228", "Oberharz am Brocken, Stadt", null], - ["150850230230", "Osterwieck, Stadt", null], - ["150850235235", "Quedlinburg, Welterbestadt", null], - ["150850330330", "Thale, Stadt", null], - ["150850370370", "Wernigerode, Stadt", null], - ["150855051090", "Ditfurt", null], - ["150855051125", "Groß Quenstedt", null], - ["150855051140", "Harsleben", null], - ["150855051160", "Hedersleben", null], - ["150855051285", "Schwanebeck, Stadt", null], - ["150855051287", "Selke-Aue", null], - ["150855051365", "Wegeleben, Stadt", null], - ["150860005005", "Biederitz", null], - ["150860015015", "Burg, Stadt", null], - ["150860035035", "Elbe-Parey", null], - ["150860040040", "Genthin, Stadt", null], - ["150860055055", "Gommern, Stadt", null], - ["150860080080", "Jerichow, Stadt", null], - ["150860140140", "Möckern, Stadt", null], - ["150860145145", "Möser", null], - ["150870015015", "Allstedt, Stadt", null], - ["150870031031", "Arnstein, Stadt", null], - ["150870130130", "Eisleben, Lutherstadt", null], - ["150870165165", "Gerbstedt, Stadt", null], - ["150870220220", "Hettstedt, Stadt", null], - ["150870275275", "Mansfeld, Stadt", null], - ["150870370370", "Sangerhausen, Stadt", null], - ["150870386386", "Seegebiet Mansfelder Land", null], - ["150870412412", "Südharz", null], - ["150875051055", "Berga", null], - ["150875051101", "Brücken-Hackpfüffel", null], - ["150875051125", "Edersleben", null], - ["150875051250", "Kelbra (Kyffhäuser), Stadt", null], - ["150875051440", "Wallhausen", null], - ["150875052010", "Ahlsdorf", null], - ["150875052045", "Benndorf", null], - ["150875052070", "Blankenheim", null], - ["150875052075", "Bornstedt", null], - ["150875052205", "Helbra", null], - ["150875052210", "Hergisdorf", null], - ["150875052260", "Klostermansfeld", null], - ["150875052470", "Wimmelburg", null], - ["150880020020", "Bad Dürrenberg, Solestadt", null], - ["150880025025", "Bad Lauchstädt, Goethestadt", null], - ["150880065065", "Braunsbedra, Stadt", null], - ["150880150150", "Kabelsketal", null], - ["150880195195", "Landsberg, Stadt", null], - ["150880205205", "Leuna, Stadt", null], - ["150880216216", "Wettin-Löbejün, Stadt", null], - ["150880220220", "Merseburg, Stadt", null], - ["150880235235", "Mücheln (Geiseltal), Stadt", null], - ["150880295295", "Petersberg", null], - ["150880305305", "Querfurt, Stadt", null], - ["150880319319", "Salzatal", null], - ["150880330330", "Schkopau", null], - ["150880365365", "Teutschenthal", null], - ["150885051030", "Barnstädt", null], - ["150885051100", "Farnstädt", null], - ["150885051250", "Nemsdorf-Göhrendorf", null], - ["150885051265", "Obhausen", null], - ["150885051340", "Schraplau, Stadt", null], - ["150885051355", "Steigra", null], - ["150890015015", "Aschersleben, Stadt", null], - ["150890026026", "Barby, Stadt", null], - ["150890030030", "Bernburg (Saale), Stadt", null], - ["150890042042", "Bördeland", null], - ["150890055055", "Calbe (Saale), Stadt", null], - ["150890175175", "Hecklingen, Stadt", null], - ["150890195195", "Könnern, Stadt", null], - ["150890235235", "Nienburg (Saale), Stadt", null], - ["150890305305", "Schönebeck (Elbe), Stadt", null], - ["150890307307", "Seeland, Stadt", null], - ["150890310310", "Staßfurt, Stadt", null], - ["150895051041", "Bördeaue", null], - ["150895051043", "Börde-Hakel", null], - ["150895051045", "Borne", null], - ["150895051075", "Egeln, Stadt", null], - ["150895051365", "Wolmirsleben", null], - ["150895052005", "Alsleben (Saale), Stadt", null], - ["150895052130", "Giersleben", null], - ["150895052165", "Güsten, Stadt", null], - ["150895052185", "Ilberstedt", null], - ["150895052245", "Plötzkau", null], - ["150900070070", "Bismark (Altmark), Stadt", null], - ["150900225225", "Havelberg, Hansestadt", null], - ["150900415415", "Osterburg (Altmark), Hansestadt", null], - ["150900535535", "Stendal, Hansestadt", null], - ["150900546546", "Tangerhütte, Stadt", null], - ["150900550550", "Tangermünde, Stadt", null], - ["150905051010", "Arneburg, Stadt", null], - ["150905051135", "Eichstedt (Altmark)", null], - ["150905051180", "Goldbeck", null], - ["150905051220", "Hassel", null], - ["150905051245", "Hohenberg-Krusemark", null], - ["150905051270", "Iden", null], - ["150905051435", "Rochau", null], - ["150905051610", "Werben (Elbe), Hansestadt", null], - ["150905052285", "Kamern", null], - ["150905052310", "Klietz", null], - ["150905052445", "Sandau (Elbe), Stadt", null], - ["150905052485", "Schollene", null], - ["150905052500", "Schönhausen (Elbe)", null], - ["150905052631", "Wust-Fischbeck", null], - ["150905053003", "Aland", null], - ["150905053007", "Altmärkische Höhe", null], - ["150905053008", "Altmärkische Wische", null], - ["150905053520", "Seehausen (Altmark), Hansestadt", null], - ["150905053635", "Zehrental", null], - ["150910010010", "Annaburg, Stadt", null], - ["150910020020", "Bad Schmiedeberg, Stadt", null], - ["150910060060", "Coswig (Anhalt), Stadt", null], - ["150910110110", "Gräfenhainichen, Stadt", null], - ["150910145145", "Jessen (Elster), Stadt", null], - ["150910160160", "Kemberg, Stadt", null], - ["150910241241", "Oranienbaum-Wörlitz, Stadt", null], - ["150910375375", "Wittenberg, Lutherstadt", null], - ["150910391391", "Zahna-Elster, Stadt", null], - ["160510000000", "Erfurt, Stadt", null], - ["160520000000", "Gera, Stadt", null], - ["160530000000", "Jena, Stadt", null], - ["160540000000", "Suhl, Stadt", null], - ["160550000000", "Weimar, Stadt", null], - ["160610045045", "Heilbad Heiligenstadt, Stadt", null], - ["160610074074", "Niederorschel", null], - ["160610115115", "Leinefelde-Worbis, Stadt", null], - ["160610116116", "Am Ohmberg", null], - ["160610117117", "Sonnenstein", null], - ["160610118118", "Dingelstädt, Stadt", null], - ["160615001003", "Berlingerode", null], - ["160615001015", "Brehme", null], - ["160615001026", "Ecklingerode", null], - ["160615001031", "Ferna", null], - ["160615001094", "Tastungen", null], - ["160615001103", "Wehnde", null], - ["160615001114", "Teistungen", null], - ["160615006017", "Breitenworbis", null], - ["160615006019", "Buhla", null], - ["160615006037", "Gernrode", null], - ["160615006044", "Haynrode", null], - ["160615006058", "Kirchworbis", null], - ["160615008001", "Arenshausen", null], - ["160615008014", "Bornhagen", null], - ["160615008021", "Burgwalde", null], - ["160615008032", "Freienhagen", null], - ["160615008033", "Fretterode", null], - ["160615008036", "Gerbershausen", null], - ["160615008048", "Hohengandern", null], - ["160615008057", "Kirchgandern", null], - ["160615008066", "Lindewerra", null], - ["160615008069", "Marth", null], - ["160615008078", "Rohrberg", null], - ["160615008082", "Rustenfelde", null], - ["160615008083", "Schachtebich", null], - ["160615008102", "Wahlhausen", null], - ["160615009012", "Bodenrode-Westhausen", null], - ["160615009034", "Geisleden", null], - ["160615009039", "Glasehausen", null], - ["160615009047", "Heuthen", null], - ["160615009049", "Hohes Kreuz", null], - ["160615009076", "Reinholterode", null], - ["160615009089", "Steinbach", null], - ["160615009107", "Wingerode", null], - ["160615012002", "Asbach-Sickenberg", null], - ["160615012007", "Birkenfelde", null], - ["160615012024", "Dietzenrode/Vatterode", null], - ["160615012028", "Eichstruth", null], - ["160615012065", "Lenterode", null], - ["160615012067", "Lutter", null], - ["160615012068", "Mackenrode", null], - ["160615012077", "Röhrig", null], - ["160615012084", "Schönhagen", null], - ["160615012091", "Steinheuterode", null], - ["160615012096", "Thalwenden", null], - ["160615012097", "Uder", null], - ["160615012111", "Wüstheuterode", null], - ["160615013018", "Büttstedt", null], - ["160615013027", "Effelder", null], - ["160615013041", "Großbartloff", null], - ["160615013063", "Küllstedt", null], - ["160615013101", "Wachstedt", null], - ["160615014023", "Dieterode", null], - ["160615014035", "Geismar", null], - ["160615014056", "Kella", null], - ["160615014062", "Krombach", null], - ["160615014075", "Pfaffschwende", null], - ["160615014085", "Schwobfeld", null], - ["160615014086", "Sickerode", null], - ["160615014098", "Volkerode", null], - ["160615014105", "Wiesenfeld", null], - ["160615014113", "Schimberg", null], - ["160620005005", "Ellrich, Stadt", null], - ["160620041041", "Nordhausen, Stadt", null], - ["160620049049", "Sollstedt", null], - ["160620062062", "Hohenstein", null], - ["160620063063", "Werther", null], - ["160620065065", "Harztor", null], - ["160625053008", "Görsbach", null], - ["160625053054", "Urbach", null], - ["160625053064", "Heringen/Helme, Stadt", null], - ["160625054009", "Großlohra", null], - ["160625054024", "Kehmstedt", null], - ["160625054026", "Kleinfurra", null], - ["160625054033", "Lipprechterode", null], - ["160625054037", "Niedergebra", null], - ["160625054066", "Bleicherode, Stadt", null], - ["160630004004", "Barchfeld-Immelborn", null], - ["160630076076", "Treffurt, Stadt", null], - ["160630078078", "Unterbreizbach", null], - ["160630082082", "Vacha, Stadt", null], - ["160630092092", "Wutha-Farnroda", null], - ["160630097097", "Gerstungen", null], - ["160630098098", "Hörselberg-Hainich", null], - ["160630099099", "Bad Liebenstein, Stadt", null], - ["160630101101", "Krayenberggemeinde", null], - ["160630103103", "Werra-Suhl-Tal, Stadt", null], - ["160630105105", "Eisenach, Stadt", null], - ["160635006006", "Berka v. d. Hainich", null], - ["160635006008", "Bischofroda", null], - ["160635006028", "Frankenroda", null], - ["160635006037", "Hallungen", null], - ["160635006046", "Krauthausen", null], - ["160635006049", "Lauterbach", null], - ["160635006058", "Nazza", null], - ["160635006104", "Amt Creuzburg, Stadt", null], - ["160635051003", "Bad Salzungen, Stadt", null], - ["160635051051", "Leimbach", null], - ["160635056011", "Buttlar", null], - ["160635056032", "Geisa, Stadt", null], - ["160635056033", "Gerstengrund", null], - ["160635056068", "Schleid", null], - ["160635057066", "Ruhla, Stadt", null], - ["160635057071", "Seebach", null], - ["160635059015", "Dermbach", null], - ["160635059023", "Empfertshausen", null], - ["160635059062", "Oechsen", null], - ["160635059084", "Weilar", null], - ["160635059086", "Wiesenthal", null], - ["160640003003", "Bad Langensalza, Stadt", null], - ["160640014014", "Dünwald", null], - ["160640046046", "Mühlhausen/Thüringen, Stadt", null], - ["160640071071", "Unstruttal", null], - ["160640072072", "Menteroda", null], - ["160640073073", "Anrode", null], - ["160645001004", "Bad Tennstedt, Stadt", null], - ["160645001005", "Ballhausen", null], - ["160645001007", "Blankenburg", null], - ["160645001009", "Bruchstedt", null], - ["160645001021", "Haussömmern", null], - ["160645001027", "Hornsömmern", null], - ["160645001033", "Kirchheilingen", null], - ["160645001038", "Kutzleben", null], - ["160645001045", "Mittelsömmern", null], - ["160645001061", "Sundhausen", null], - ["160645001062", "Tottleben", null], - ["160645001064", "Urleben", null], - ["160645051019", "Großvargula", null], - ["160645051022", "Herbsleben", null], - ["160645052055", "Rodeberg", null], - ["160645052074", "Südeichsfeld", null], - ["160645053032", "Kammerforst", null], - ["160645053053", "Oppershausen", null], - ["160645053075", "Vogtei", null], - ["160645054058", "Schönstedt", null], - ["160645054076", "Unstrut-Hainich", null], - ["160645055037", "Körner", null], - ["160645055043", "Marolterode", null], - ["160645055077", "Nottertal-Heilinger Höhen, Stadt", null], - ["160650003003", "Bad Frankenhausen/Kyffhäuser, Stadt", null], - ["160650032032", "Helbedündorf", null], - ["160650067067", "Sondershausen, Stadt", null], - ["160650085085", "Kyffhäuserland", null], - ["160650087087", "Roßleben-Wiehe, Stadt", null], - ["160650089089", "Greußen, Stadt", null], - ["160655002012", "Clingen, Stadt", null], - ["160655002048", "Niederbösa", null], - ["160655002051", "Oberbösa", null], - ["160655002074", "Topfstedt", null], - ["160655002075", "Trebra", null], - ["160655002077", "Wasserthaleben", null], - ["160655002079", "Westgreußen", null], - ["160655052001", "Abtsbessingen", null], - ["160655052005", "Bellstedt", null], - ["160655052014", "Ebeleben, Stadt", null], - ["160655052018", "Freienbessingen", null], - ["160655052038", "Holzsußra", null], - ["160655052058", "Rockstedt", null], - ["160655055008", "Borxleben", null], - ["160655055019", "Gehofen", null], - ["160655055042", "Kalbsrieth", null], - ["160655055046", "Mönchpfiffel-Nikolausrieth", null], - ["160655055056", "Reinsdorf", null], - ["160655055086", "Artern, Stadt", null], - ["160655056016", "Etzleben", null], - ["160655056052", "Oberheldrungen", null], - ["160655056088", "An der Schmücke, Stadt", null], - ["160660023023", "Floh-Seligenthal", null], - ["160660047047", "Oberhof, Stadt", null], - ["160660063063", "Schmalkalden, Kurort, Stadt", null], - ["160660069069", "Steinbach-Hallenberg, Kurort, Stadt", null], - ["160660074074", "Brotterode-Trusetal, Stadt", null], - ["160660092092", "Zella-Mehlis, Stadt", null], - ["160660093093", "Rhönblick", null], - ["160660094094", "Grabfeld", null], - ["160665005012", "Birx", null], - ["160665005019", "Erbenhausen", null], - ["160665005024", "Frankenheim/Rhön", null], - ["160665005052", "Oberweid", null], - ["160665005095", "Kaltennordheim, Stadt", null], - ["160665013025", "Friedelshausen", null], - ["160665013041", "Mehmels", null], - ["160665013064", "Schwallungen", null], - ["160665013086", "Wasungen, Stadt", null], - ["160665014005", "Belrieth", null], - ["160665014015", "Christes", null], - ["160665014016", "Dillstädt", null], - ["160665014017", "Einhausen", null], - ["160665014018", "Ellingshausen", null], - ["160665014038", "Kühndorf", null], - ["160665014039", "Leutersdorf", null], - ["160665014045", "Neubrunn", null], - ["160665014049", "Obermaßfeld-Grimmenthal", null], - ["160665014057", "Ritschenhausen", null], - ["160665014058", "Rohr", null], - ["160665014065", "Schwarza", null], - ["160665014079", "Utendorf", null], - ["160665014081", "Vachdorf", null], - ["160665050042", "Meiningen, Stadt", null], - ["160665050056", "Rippershausen", null], - ["160665050073", "Sülzfeld", null], - ["160665050076", "Untermaßfeld", null], - ["160665051013", "Breitungen/Werra", null], - ["160665051022", "Fambach", null], - ["160665051059", "Rosa", null], - ["160665051061", "Roßdorf", null], - ["160670019019", "Friedrichroda, Stadt", null], - ["160670029029", "Gotha, Stadt", null], - ["160670064064", "Bad Tabarz", null], - ["160670065065", "Tambach-Dietharz/Thür. Wald, Stadt", null], - ["160670072072", "Waltershausen, Stadt", null], - ["160670087087", "Nesse-Apfelstädt", null], - ["160670088088", "Hörsel", null], - ["160675007004", "Bienstädt", null], - ["160675007016", "Eschenbergen", null], - ["160675007022", "Friemar", null], - ["160675007047", "Molschleben", null], - ["160675007052", "Nottleben", null], - ["160675007055", "Pferdingsleben", null], - ["160675007068", "Tröchtelborn", null], - ["160675007071", "Tüttleben", null], - ["160675007082", "Zimmernsupra", null], - ["160675012009", "Dachwig", null], - ["160675012011", "Döllstädt", null], - ["160675012026", "Gierstädt", null], - ["160675012033", "Großfahner", null], - ["160675012067", "Tonna", null], - ["160675050044", "Luisenthal", null], - ["160675050053", "Ohrdruf, Stadt", null], - ["160675052059", "Schwabhausen", null], - ["160675052089", "Drei Gleichen", null], - ["160675053063", "Sonneborn", null], - ["160675053091", "Nessetal", null], - ["160675054013", "Emleben", null], - ["160675054036", "Herrenhof", null], - ["160675054092", "Georgenthal", null], - ["160680034034", "Kölleda, Stadt", null], - ["160680051051", "Sömmerda, Stadt", null], - ["160680058058", "Weißensee, Stadt", null], - ["160680063063", "Buttstädt", null], - ["160685002002", "Andisleben", null], - ["160685002014", "Gebesee, Stadt", null], - ["160685002045", "Ringleben", null], - ["160685002057", "Walschleben", null], - ["160685005005", "Büchel", null], - ["160685005015", "Griefstedt", null], - ["160685005022", "Günstedt", null], - ["160685005043", "Riethgen", null], - ["160685005064", "Kindelbrück", null], - ["160685006019", "Großneuhausen", null], - ["160685006033", "Kleinneuhausen", null], - ["160685006041", "Ostramondra", null], - ["160685006042", "Rastenberg, Stadt", null], - ["160685009013", "Gangloffsömmern", null], - ["160685009025", "Haßleben", null], - ["160685009044", "Riethnordhausen", null], - ["160685009049", "Schwerstedt", null], - ["160685009053", "Straußfurt", null], - ["160685009059", "Werningshausen", null], - ["160685009062", "Wundersleben", null], - ["160685012001", "Alperstedt", null], - ["160685012007", "Eckstedt", null], - ["160685012017", "Großmölsen", null], - ["160685012021", "Großrudestedt", null], - ["160685012032", "Kleinmölsen", null], - ["160685012036", "Markvippach", null], - ["160685012037", "Nöda", null], - ["160685012039", "Ollendorf", null], - ["160685012048", "Schloßvippach", null], - ["160685012052", "Sprötau", null], - ["160685012055", "Udestedt", null], - ["160685012056", "Vogelsberg", null], - ["160685050009", "Elxleben", null], - ["160685050061", "Witterda", null], - ["160690012012", "Eisfeld, Stadt", null], - ["160690024024", "Hildburghausen, Stadt", null], - ["160690042042", "Schleusegrund", null], - ["160690043043", "Schleusingen, Stadt", null], - ["160690053053", "Veilsdorf", null], - ["160690061061", "Masserberg", null], - ["160690062062", "Römhild, Stadt", null], - ["160695002001", "Ahlstädt", null], - ["160695002003", "Beinerstadt", null], - ["160695002004", "Bischofrod", null], - ["160695002008", "Dingsleben", null], - ["160695002009", "Ehrenberg", null], - ["160695002011", "Eichenberg", null], - ["160695002016", "Grimmelshausen", null], - ["160695002017", "Grub", null], - ["160695002021", "Henfstädt", null], - ["160695002025", "Kloster Veßra", null], - ["160695002026", "Lengfeld", null], - ["160695002028", "Marisfeld", null], - ["160695002035", "Oberstadt", null], - ["160695002037", "Reurieth", null], - ["160695002044", "Schmeheim", null], - ["160695002047", "St.Bernhard", null], - ["160695002051", "Themar, Stadt", null], - ["160695004041", "Schlechtsart", null], - ["160695004046", "Schweickershausen", null], - ["160695004049", "Straufhain", null], - ["160695004052", "Ummerstadt, Stadt", null], - ["160695004056", "Westhausen", null], - ["160695004063", "Heldburg, Stadt", null], - ["160695051006", "Brünn/Thür.", null], - ["160695051058", "Auengrund", null], - ["160700004004", "Arnstadt, Stadt", null], - ["160700028028", "Amt Wachsenburg", null], - ["160700029029", "Ilmenau, Stadt", null], - ["160700048048", "Stadtilm, Stadt", null], - ["160700057057", "Geratal", null], - ["160700058058", "Großbreitenbach, Stadt", null], - ["160705002011", "Elgersburg", null], - ["160705002034", "Martinroda", null], - ["160705002043", "Plaue, Stadt", null], - ["160705009001", "Alkersleben", null], - ["160705009006", "Bösleben-Wüllersleben", null], - ["160705009008", "Dornheim", null], - ["160705009012", "Elleben", null], - ["160705009013", "Elxleben", null], - ["160705009041", "Osthausen-Wülfershausen", null], - ["160705009054", "Witzleben", null], - ["160710001001", "Apolda, Stadt", null], - ["160710003003", "Bad Berka, Stadt", null], - ["160710008008", "Blankenhain, Stadt", null], - ["160710101101", "Ilmtal-Weinstraße", null], - ["160710103103", "Grammetal", null], - ["160715007032", "Hohenfelden", null], - ["160715007043", "Klettbach", null], - ["160715007046", "Kranichfeld, Stadt", null], - ["160715007059", "Nauendorf", null], - ["160715007079", "Rittersdorf", null], - ["160715007087", "Tonndorf", null], - ["160715008009", "Buchfart", null], - ["160715008013", "Döbritschen", null], - ["160715008019", "Frankendorf", null], - ["160715008025", "Großschwabhausen", null], - ["160715008027", "Hammerstedt", null], - ["160715008031", "Hetschburg", null], - ["160715008037", "Kapellendorf", null], - ["160715008038", "Kiliansroda", null], - ["160715008042", "Kleinschwabhausen", null], - ["160715008049", "Lehnstedt", null], - ["160715008053", "Magdala, Stadt", null], - ["160715008055", "Mechelroda", null], - ["160715008056", "Mellingen", null], - ["160715008071", "Oettern", null], - ["160715008089", "Umpferstedt", null], - ["160715008093", "Vollersroda", null], - ["160715008095", "Wiegendorf", null], - ["160715051004", "Bad Sulza, Stadt", null], - ["160715051015", "Eberstedt", null], - ["160715051022", "Großheringen", null], - ["160715051064", "Niedertrebra", null], - ["160715051069", "Obertrebra", null], - ["160715051077", "Rannstedt", null], - ["160715051083", "Schmiedehausen", null], - ["160715053005", "Ballstedt", null], - ["160715053017", "Ettersburg", null], - ["160715053061", "Neumark, Stadt", null], - ["160715053102", "Am Ettersberg", null], - ["160720011011", "Lauscha, Stadt", null], - ["160720015015", "Schalkau, Stadt", null], - ["160720018018", "Sonneberg, Stadt", null], - ["160720019019", "Steinach, Stadt", null], - ["160720023023", "Frankenblick", null], - ["160720024024", "Föritztal", null], - ["160725051006", "Goldisthal", null], - ["160725051013", "Neuhaus am Rennweg, Stadt", null], - ["160730005005", "Bad Blankenburg, Stadt", null], - ["160730076076", "Rudolstadt, Stadt", null], - ["160730077077", "Saalfeld/Saale, Stadt", null], - ["160730106106", "Leutenberg, Stadt", null], - ["160730109109", "Uhlstädt-Kirchhasel", null], - ["160730111111", "Unterwellenborn", null], - ["160735005028", "Gräfenthal, Stadt", null], - ["160735005046", "Lehesten, Stadt", null], - ["160735005067", "Probstzella", null], - ["160735012013", "Cursdorf", null], - ["160735012014", "Deesbach", null], - ["160735012017", "Döschnitz", null], - ["160735012037", "Katzhütte", null], - ["160735012055", "Meura", null], - ["160735012074", "Rohrbach", null], - ["160735012082", "Schwarzburg", null], - ["160735012084", "Sitzendorf", null], - ["160735012094", "Unterweißbach", null], - ["160735012113", "Schwarzatal, Stadt", null], - ["160735051002", "Altenbeuthen", null], - ["160735051035", "Hohenwarte", null], - ["160735051038", "Kaulsdorf", null], - ["160735051107", "Drognitz", null], - ["160735054001", "Allendorf", null], - ["160735054006", "Bechstedt", null], - ["160735054112", "Königsee, Stadt", null], - ["160740044044", "Kahla, Stadt", null], - ["160745005012", "Crossen an der Elster", null], - ["160745005038", "Hartmannsdorf", null], - ["160745005039", "Heideland", null], - ["160745005072", "Rauda", null], - ["160745005092", "Silbitz", null], - ["160745005106", "Walpernhain", null], - ["160745005116", "Schkölen, Stadt", null], - ["160745007007", "Bremsnitz", null], - ["160745007017", "Eineborn", null], - ["160745007022", "Geisenhain", null], - ["160745007024", "Gneus", null], - ["160745007029", "Großbockedra", null], - ["160745007045", "Karlsdorf", null], - ["160745007046", "Kleinbockedra", null], - ["160745007047", "Kleinebersdorf", null], - ["160745007053", "Lippersdorf-Erdmannsdorf", null], - ["160745007056", "Meusebach", null], - ["160745007064", "Oberbodnitz", null], - ["160745007066", "Ottendorf", null], - ["160745007071", "Rattelsdorf", null], - ["160745007074", "Rausdorf", null], - ["160745007077", "Renthendorf", null], - ["160745007097", "Tautendorf", null], - ["160745007101", "Tissa", null], - ["160745007102", "Trockenborn-Wolfersdorf", null], - ["160745007103", "Tröbnitz", null], - ["160745007104", "Unterbodnitz", null], - ["160745007107", "Waltersdorf", null], - ["160745007108", "Weißbach", null], - ["160745011002", "Altenberga", null], - ["160745011004", "Bibra", null], - ["160745011008", "Bucha", null], - ["160745011016", "Eichenberg", null], - ["160745011021", "Freienorla", null], - ["160745011031", "Großeutersdorf", null], - ["160745011033", "Großpürschütz", null], - ["160745011034", "Gumperda", null], - ["160745011042", "Hummelshain", null], - ["160745011048", "Kleineutersdorf", null], - ["160745011049", "Laasdorf", null], - ["160745011052", "Lindig", null], - ["160745011057", "Milda", null], - ["160745011065", "Orlamünde, Stadt", null], - ["160745011076", "Reinstädt", null], - ["160745011079", "Rothenstein", null], - ["160745011087", "Schöps", null], - ["160745011089", "Seitenroda", null], - ["160745011095", "Sulza", null], - ["160745011114", "Zöllnitz", null], - ["160745014041", "Hermsdorf, Stadt", null], - ["160745014059", "Mörsdorf", null], - ["160745014075", "Reichenbach", null], - ["160745014084", "Schleifreisen", null], - ["160745014093", "St.Gangloff", null], - ["160745015011", "Dornburg-Camburg, Stadt", null], - ["160745015019", "Frauenprießnitz", null], - ["160745015026", "Golmsdorf", null], - ["160745015032", "Großlöbichau", null], - ["160745015036", "Hainichen", null], - ["160745015043", "Jenalöbnitz", null], - ["160745015051", "Lehesten", null], - ["160745015054", "Löberschütz", null], - ["160745015063", "Neuengönna", null], - ["160745015096", "Tautenburg", null], - ["160745015099", "Thierschneck", null], - ["160745015112", "Wichmar", null], - ["160745015113", "Zimmern", null], - ["160745050058", "Möckern", null], - ["160745050081", "Ruttersdorf-Lotschen", null], - ["160745050094", "Stadtroda, Stadt", null], - ["160745051009", "Bürgel, Stadt", null], - ["160745051028", "Graitschen b. Bürgel", null], - ["160745051061", "Nausnitz", null], - ["160745051068", "Poxdorf", null], - ["160745052018", "Eisenberg, Stadt", null], - ["160745052025", "Gösen", null], - ["160745052037", "Hainspitz", null], - ["160745052055", "Mertendorf", null], - ["160745052067", "Petersberg", null], - ["160745052073", "Rauschwitz", null], - ["160745053001", "Albersdorf", null], - ["160745053003", "Bad Klosterlausnitz", null], - ["160745053005", "Bobeck", null], - ["160745053082", "Scheiditz", null], - ["160745053085", "Schlöben", null], - ["160745053086", "Schöngleina", null], - ["160745053091", "Serba", null], - ["160745053098", "Tautenhain", null], - ["160745053105", "Waldeck", null], - ["160745053109", "Weißenborn", null], - ["160750046046", "Hirschberg, Stadt", null], - ["160750062062", "Bad Lobenstein, Stadt", null], - ["160750085085", "Pößneck, Stadt", null], - ["160750098098", "Schleiz, Stadt", null], - ["160750131131", "Gefell, Stadt", null], - ["160750132132", "Tanna, Stadt", null], - ["160750133133", "Wurzbach, Stadt", null], - ["160750134134", "Remptendorf", null], - ["160750135135", "Saalburg-Ebersdorf, Stadt", null], - ["160750136136", "Rosenthal am Rennsteig", null], - ["160755004014", "Dittersdorf", null], - ["160755004033", "Görkwitz", null], - ["160755004034", "Göschitz", null], - ["160755004048", "Kirschkau", null], - ["160755004063", "Löhma", null], - ["160755004068", "Moßbach", null], - ["160755004072", "Neundorf (bei Schleiz)", null], - ["160755004076", "Oettersdorf", null], - ["160755004083", "Plothen", null], - ["160755004084", "Pörmitz", null], - ["160755004109", "Tegau", null], - ["160755004119", "Volkmannsdorf", null], - ["160755005006", "Bodelwitz", null], - ["160755005016", "Döbritz", null], - ["160755005031", "Gertewitz", null], - ["160755005039", "Grobengereuth", null], - ["160755005054", "Langenorla", null], - ["160755005056", "Lausnitz b. Neustadt an der Orla", null], - ["160755005074", "Nimritz", null], - ["160755005075", "Oberoppurg", null], - ["160755005077", "Oppurg", null], - ["160755005087", "Quaschwitz", null], - ["160755005105", "Solkwitz", null], - ["160755005121", "Weira", null], - ["160755005124", "Wernburg", null], - ["160755011019", "Dreitzsch", null], - ["160755011029", "Geroda", null], - ["160755011057", "Lemnitz", null], - ["160755011065", "Miesitz", null], - ["160755011066", "Mittelpöllnitz", null], - ["160755011093", "Rosendorf", null], - ["160755011099", "Schmieritz", null], - ["160755011114", "Tömmelsdorf", null], - ["160755011116", "Triptis, Stadt", null], - ["160755013023", "Eßbach", null], - ["160755013035", "Gössitz", null], - ["160755013047", "Keila", null], - ["160755013069", "Moxa", null], - ["160755013079", "Paska", null], - ["160755013081", "Peuschen", null], - ["160755013088", "Ranis, Stadt", null], - ["160755013101", "Schmorda", null], - ["160755013102", "Schöndorf", null], - ["160755013103", "Seisla", null], - ["160755013125", "Wilhelmsdorf", null], - ["160755013127", "Ziegenrück, Stadt", null], - ["160755013129", "Krölpa", null], - ["160755050051", "Kospoda", null], - ["160755050073", "Neustadt an der Orla, Stadt", null], - ["160760004004", "Berga/Elster, Stadt", null], - ["160760022022", "Greiz, Stadt", null], - ["160760061061", "Ronneburg, Stadt", null], - ["160760088088", "Harth-Pöllnitz", null], - ["160760089089", "Kraftsdorf", null], - ["160760092092", "Auma-Weidatal, Stadt", null], - ["160760093093", "Mohlsdorf-Teichwolframsdorf", null], - ["160765004009", "Braunichswalde", null], - ["160765004017", "Endschütz", null], - ["160765004019", "Gauern", null], - ["160765004027", "Hilbersdorf", null], - ["160765004034", "Kauern", null], - ["160765004043", "Linda b. Weida", null], - ["160765004055", "Paitzdorf", null], - ["160765004062", "Rückersdorf", null], - ["160765004069", "Seelingstädt", null], - ["160765004074", "Teichwitz", null], - ["160765004084", "Wünschendorf/Elster", null], - ["160765006007", "Bocka", null], - ["160765006033", "Hundhaupten", null], - ["160765006042", "Lederhose", null], - ["160765006044", "Lindenkreuz", null], - ["160765006049", "Münchenbernsdorf, Stadt", null], - ["160765006064", "Saara", null], - ["160765006068", "Schwarzbach", null], - ["160765006086", "Zedlitz", null], - ["160765008006", "Bethenhausen", null], - ["160765008008", "Brahmenau", null], - ["160765008023", "Großenstein", null], - ["160765008028", "Hirschfeld", null], - ["160765008036", "Korbußen", null], - ["160765008058", "Pölzig", null], - ["160765008059", "Reichstädt", null], - ["160765008067", "Schwaara", null], - ["160765051003", "Bad Köstritz, Stadt", null], - ["160765051012", "Caaschwitz", null], - ["160765051026", "Hartmannsdorf", null], - ["160765053014", "Crimla", null], - ["160765053079", "Weida, Stadt", null], - ["160765054041", "Langenwolschendorf", null], - ["160765054081", "Weißendorf", null], - ["160765054087", "Zeulenroda-Triebes, Stadt", null], - ["160765056029", "Hohenleuben, Stadt", null], - ["160765056038", "Kühdorf", null], - ["160765056039", "Langenwetzendorf", null], - ["160770001001", "Altenburg, Stadt", null], - ["160770028028", "Lucka, Stadt", null], - ["160770032032", "Meuselwitz, Stadt", null], - ["160775004005", "Fockendorf", null], - ["160775004007", "Gerstenberg", null], - ["160775004015", "Haselbach", null], - ["160775004048", "Treben", null], - ["160775004052", "Windischleuba", null], - ["160775005008", "Göhren", null], - ["160775005009", "Göllnitz", null], - ["160775005022", "Kriebitzsch", null], - ["160775005027", "Lödla", null], - ["160775005031", "Mehna", null], - ["160775005034", "Monstab", null], - ["160775005042", "Rositz", null], - ["160775005044", "Starkenberg", null], - ["160775009016", "Heukewalde", null], - ["160775009018", "Jonaswalde", null], - ["160775009026", "Löbichau", null], - ["160775009041", "Posterstein", null], - ["160775009047", "Thonhausen", null], - ["160775009049", "Vollmershain", null], - ["160775050012", "Gößnitz, Stadt", null], - ["160775050017", "Heyersdorf", null], - ["160775050039", "Ponitz", null], - ["160775051011", "Göpfersdorf", null], - ["160775051023", "Langenleuba-Niederhain", null], - ["160775051036", "Nobitz", null], - ["160775052003", "Dobitschen", null], - ["160775052043", "Schmölln, Stadt", null] - ] -} diff --git a/tests/components/nina/fixtures/sample_warning_details.json b/tests/components/nina/fixtures/sample_warning_details.json deleted file mode 100644 index 48a2e6964c7..00000000000 --- a/tests/components/nina/fixtures/sample_warning_details.json +++ /dev/null @@ -1,289 +0,0 @@ -{ - "mow.DE-BW-S-SE018-20211102-18-001": { - "identifier": "mow.DE-BW-S-SE018-20211102-18-001", - "sender": "DE-NW-BN-SE030", - "sent": "2021-11-02T20:07:16+01:00", - "status": "Actual", - "msgType": "Update", - "scope": "Public", - "code": [ - "DVN:1", - "medien_ueberregional", - "nina", - "Materna:noPush", - "Materna:noMirror" - ], - "references": "DE-NW-BN-SE030-20200506-30-001 DE-NW-BN-SE030-20200422-30-000 DE-NW-BN-SE030-20200420-30-001 DE-NW-BN-SE030-20200416-30-001 DE-NW-BN-SE030-20200403-30-000 DE-NW-BN-W003,mow.DE-NW-BN-SE030-20200506-30-001 mow.DE-NW-BN-SE030-20200422-30-000 mow.DE-NW-BN-SE030-20200420-30-001 mow.DE-NW-BN-SE030-20200416-30-001 mow.DE-NW-BN-SE030-20200403-30-000 mow.DE-NW-BN-W003-20200403-000,2020-04-03T00:00:00+00:00", - "info": [ - { - "language": "DE", - "category": ["Health"], - "event": "Gefahreninformation", - "urgency": "Immediate", - "severity": "Minor", - "certainty": "Observed", - "eventCode": [ - { - "valueName": "profile:DE-BBK-EVENTCODE", - "value": "BBK-EVC-040" - } - ], - "headline": "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen", - "description": "Die Zahl der mit dem Corona-Virus infizierten Menschen steigt gegenwärtig stark an. Es wächst daher die Gefahr einer weiteren Verbreitung der Infektion und - je nach Einzelfall - auch von schweren Erkrankungen.", - "instruction": "Waschen sich regelmäßig und gründlich die Hände.", - "contact": "Weitere Informationen und Empfehlungen finden Sie im Corona-Informations-Bereich der Warn-App NINA. Beachten Sie auch die Internetseiten der örtlichen Gesundheitsbehörde (Stadt- bzw. Kreisverwaltung) Ihres Aufenthaltsortes", - "parameter": [ - { - "valueName": "instructionText", - "value": "- Beachten Sie die AHA + A + L - Regeln:\nAbstand halten - 1,5 m Mindestabstand beachten, Körperkontakt vermeiden! \nHygiene - regelmäßiges Händewaschen, Husten- und Nieshygiene beachten! \nAlltagsmaske (Mund-Nase-Bedeckung) tragen! \nApp - installieren und nutzen Sie die Corona-Warn-App! \nLüften: Sorgen Sie für eine regelmäßige und gründliche Lüftung von Räumen - auch und gerade in der kommenden kalten Jahreszeit! \n- Bitte folgen Sie den behördlichen Anordnungen. \n- Husten und niesen Sie in ein Taschentuch oder in die Armbeuge. \n- Bleiben Sie bei Erkältungssymptomen nach Möglichkeit zu Hause. Kontaktieren Sie Ihre Hausarztpraxis per Telefon oder wenden sich an die Telefonnummer 116117 des Ärztlichen Bereitschaftsdienstes und besprechen Sie das weitere Vorgehen. Gehen Sie nicht unaufgefordert in eine Arztpraxis oder ins Krankenhaus. \n- Seien Sie kritisch: Informieren Sie sich nur aus gesicherten Quellen." - }, - { - "valueName": "warnVerwaltungsbereiche", - "value": "130000000000,140000000000,160000000000,110000000000,020000000000,070000000000,030000000000,050000000000,080000000000,120000000000,010000000000,150000000000,040000000000,060000000000,090000000000,100000000000" - }, - { - "valueName": "instructionCode", - "value": "BBK-ISC-082" - }, - { - "valueName": "sender_langname", - "value": "BBK, Nationale Warnzentrale Bonn" - }, - { - "valueName": "sender_signature", - "value": "Bundesamt für Bevölkerungsschutz und Katastrophenhilfe\nNationale Warnzentrale Bonn\nhttps://warnung.bund.de" - }, - { - "valueName": "PHGEM", - "value": "1+11057,100001" - }, - { - "valueName": "ZGEM", - "value": "1+11057,100001" - } - ], - "area": [ - { - "areaDesc": "Bundesland: Freie Hansestadt Bremen, Land Berlin, Land Hessen, Land Nordrhein-Westfalen, Land Brandenburg, Freistaat Bayern, Land Mecklenburg-Vorpommern, Land Rheinland-Pfalz, Freistaat Sachsen, Land Schleswig-Holstein, Freie und Hansestadt Hamburg, Freistaat Thüringen, Land Niedersachsen, Land Saarland, Land Sachsen-Anhalt, Land Baden-Württemberg", - "geocode": [ - { - "valueName": "AreaId", - "value": "0" - } - ] - } - ] - } - ] - }, - "mow.DE-NW-BN-SE030-20201014-30-000": { - "identifier": "mow.DE-NW-BN-SE030-20201014-30-000", - "sender": "opendata@dwd.de", - "sent": "2021-10-11T05:20:00+01:00", - "status": "Actual", - "msgType": "Alert", - "source": "PVW", - "scope": "Public", - "code": [ - "DVN:2", - "id:2.49.0.0.276.0.DWD.PVW.1645004040000.5a168da8-ac20-4b6d-86be-d616526a7914" - ], - "info": [ - { - "language": "de-DE", - "category": ["Met"], - "event": "STURMBÖEN", - "responseType": ["Prepare"], - "urgency": "Immediate", - "severity": "Moderate", - "certainty": "Likely", - "eventCode": [ - { - "valueName": "PROFILE_VERSION", - "value": "2.1.11" - }, - { - "valueName": "LICENSE", - "value": "© GeoBasis-DE / BKG 2019 (Daten modifiziert)" - }, - { - "valueName": "II", - "value": "52" - }, - { - "valueName": "GROUP", - "value": "WIND" - }, - { - "valueName": "AREA_COLOR", - "value": "251 140 0" - } - ], - "effective": "2021-11-01T03:20:00+01:00", - "onset": "2021-11-01T05:20:00+01:00", - "expires": "3021-11-22T05:19:00+01:00", - "senderName": "Deutscher Wetterdienst", - "headline": "Ausfall Notruf 112", - "description": "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.", - "web": "https://www.wettergefahren.de", - "contact": "Deutscher Wetterdienst", - "parameter": [ - { - "valueName": "gusts", - "value": "70-85 [km/h]" - }, - { - "valueName": "exposed gusts", - "value": "<90 [km/h]" - }, - { - "valueName": "wind direction", - "value": "west" - }, - { - "valueName": "PHGEM", - "value": "3243+168,3413+1,3424+52,3478+1,3495+2,3499,3639+2527,6168+1,6175+22,6199+36,6238,6241+7,6256,9956+184,10142,10154,10164+7,10173,10176+6,10186+1,10195+2,10199,10201+6,10214+4,10220,10249+117,10368,10373+2,10425+9,10436+1,10440+8,10450+1,10453+7,10462+1,10467+5,10474+2,10484+5,10773+68,10843+2,10847+9,10858,10867+8,10878+1,10882+68,10952+7,10961+2,11046,11056+1" - }, - { - "valueName": "ZGEM", - "value": "3243+168,3413+1,3424+52,3478+1,3495+2,3499,3639+2527,6168+1,6175+22,6199+36,6238,6241+7,6256,9956+184,10142,10154,10164+7,10173,10176+6,10186+1,10195+2,10199,10201+6,10214+4,10220,10249+117,10368,10373+2,10425+9,10436+1,10440+8,10450+1,10453+7,10462+1,10467+5,10474+2,10484+5,10773+68,10843+2,10847+9,10858,10867+8,10878+1,10882+68,10952+7,10961+2,11046,11056+1" - } - ], - "area": [ - { - "areaDesc": "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere." - } - ] - } - ] - }, - "mow.DE-NW-BN-SE030-20201014-30-011": { - "identifier": "mow.DE-NW-BN-SE030-20201014-30-011", - "sender": "opendata@dwd.de", - "sent": "2021-10-11T05:21:00+01:00", - "status": "Actual", - "msgType": "Alert", - "source": "PVW", - "scope": "Public", - "code": [ - "DVN:2", - "id:2.49.0.0.276.0.DWD.PVW.1645004040000.5a168da8-ac20-4b6d-86be-d616526a7914" - ], - "info": [ - { - "language": "de-DE", - "category": ["Met"], - "event": "STURMBÖEN", - "responseType": ["Prepare"], - "urgency": "Immediate", - "severity": "Moderate", - "certainty": "Likely", - "eventCode": [ - { - "valueName": "PROFILE_VERSION", - "value": "2.1.11" - }, - { - "valueName": "LICENSE", - "value": "© GeoBasis-DE / BKG 2019 (Daten modifiziert)" - }, - { - "valueName": "II", - "value": "52" - }, - { - "valueName": "GROUP", - "value": "WIND" - }, - { - "valueName": "AREA_COLOR", - "value": "251 140 0" - } - ], - "effective": "2021-11-01T03:20:00+01:00", - "onset": "2021-11-01T05:20:00+01:00", - "expires": "3021-11-22T05:19:00+01:00", - "senderName": "Deutscher Wetterdienst", - "headline": "Ausfall Notruf 112", - "description": "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.", - "instruction": "ACHTUNG! Hinweis auf mögliche Gefahren: Es können zum Beispiel einzelne Äste herabstürzen. Achten Sie besonders auf herabfallende Gegenstände.", - "web": "https://www.wettergefahren.de", - "contact": "Deutscher Wetterdienst", - "parameter": [ - { - "valueName": "gusts", - "value": "70-85 [km/h]" - }, - { - "valueName": "exposed gusts", - "value": "<90 [km/h]" - }, - { - "valueName": "wind direction", - "value": "west" - }, - { - "valueName": "PHGEM", - "value": "3243+168,3413+1,3424+52,3478+1,3495+2,3499,3639+2527,6168+1,6175+22,6199+36,6238,6241+7,6256,9956+184,10142,10154,10164+7,10173,10176+6,10186+1,10195+2,10199,10201+6,10214+4,10220,10249+117,10368,10373+2,10425+9,10436+1,10440+8,10450+1,10453+7,10462+1,10467+5,10474+2,10484+5,10773+68,10843+2,10847+9,10858,10867+8,10878+1,10882+68,10952+7,10961+2,11046,11056+1" - }, - { - "valueName": "ZGEM", - "value": "3243+168,3413+1,3424+52,3478+1,3495+2,3499,3639+2527,6168+1,6175+22,6199+36,6238,6241+7,6256,9956+184,10142,10154,10164+7,10173,10176+6,10186+1,10195+2,10199,10201+6,10214+4,10220,10249+117,10368,10373+2,10425+9,10436+1,10440+8,10450+1,10453+7,10462+1,10467+5,10474+2,10484+5,10773+68,10843+2,10847+9,10858,10867+8,10878+1,10882+68,10952+7,10961+2,11046,11056+1" - } - ], - "area": [ - { - "areaDesc": "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere." - } - ] - } - ] - }, - "biw.BIWAPP-69634": { - "identifier": "biw.BIWAPP-69634", - "sender": "CAP@biwapp.de", - "sent": "1999-08-07T10:59:00+02:00", - "status": "Actual", - "msgType": "Alert", - "scope": "Public", - "code": ["DVN:2", "BIWAPP"], - "info": [ - { - "language": "DE", - "category": ["Other"], - "event": "4", - "urgency": "Unknown", - "severity": "Minor", - "certainty": "Unknown", - "expires": "2002-08-07T10:59:00+02:00", - "headline": "Geflügelpest im Landkreis Cuxhaven - Teile des Landkreises Osterholz zur Überwachungszone erklärt", - "description": "In Beverstedt im Landkreis Cuxhaven ist am 20. Juli 2022 in einer Geflügelhaltung der Ausbruch der Geflügelpest (Vogelgrippe, Aviäre Influenza) amtlich festgestellt worden. Durch die geografische Nähe des Ausbruchsbetriebes zum Gebiet des Landkreises Osterholz musste das Veterinäramt des Landkreises zum Schutz vor einer Ausbreitung der Geflügelpest auch für sein Gebiet ein Restriktionsgebiet festlegen. Rund um den Ausbruchsort wurde eine Überwachungszone ausgewiesen. Eine entsprechende Tierseuchenbehördliche Allgemeinverfügung wurde vom Landkreis Osterholz erlassen und tritt am 23.07.2022 in Kraft.
 
Die Überwachungszone mit einem Radius von mindestens zehn Kilometern um den Ausbruchsbetrieb erstreckt sich im Landkreis Osterholz innerhalb der Samtgemeinde Hambergen auf die Mitgliedsgemeinden Axstedt, Holste und Lübberstedt. Die vorgenannten Gemeinden sind vollständig zur Überwachungszone erklärt worden. Der genaue Grenzverlauf des Gebietes kann auch der interaktiven Karte im Internet entnommen werden.
 
In der Überwachungszone liegen im Landkreis Osterholz rund 70 Geflügelhaltungen mit einem Gesamtbestand von rund 1.800 Tieren. Sie alle unterliegen mit der Allgemeinverfügung der sogenannten amtlichen Beobachtung. Für die Betriebe sind die Biosicherheitsmaßnahmen einzuhalten. Dazu zählen insbesondere Hygienemaßnahmen im laufenden Betrieb und eine ordnungsgemäße Schadnagerbekämpfung.
 
Das Verbringen von Vögeln, Fleisch von Geflügel, Eiern und sonstige Nebenprodukte von Geflügel in und aus Betrieben in der Überwachungszone ist verboten. Auch Geflügeltransporte sind in der Überwachungszone verboten. Jeder Verdacht der Erkrankung auf Geflügelpest ist zudem dem Veterinäramt des Landkreises Osterholz unter der E-Mail-Adresse veterinaeramt@landkreis-osterholz.de sofort zu melden. Alle Hinweise, die innerhalb der Überwachungszone zu beachten sind, sind unter www.landkreis-osterholz.de/gefluegelpest zusammengefasst dargestellt.
 
Die Veterinärbehörde weist zudem darauf hin, dass sämtliche Geflügelhaltungen – Hühner, Enten, Gänse, Fasane, Perlhühner, Rebhühner, Truthühner, Wachteln oder Laufvögel – der zuständigen Behörde angezeigt werden müssen. Wer dies bisher noch nicht gemacht hat und über keine Registriernummer für seinen Geflügelbestand verfügt, sollte die Meldung über das Veterinäramt umgehend nachholen.
 
Das Beobachtungsgebiet kann frühestens 30 Tage nach der Grobreinigung des Ausbruchsbetriebes wieder aufgehoben werden. Hierüber wird der Landkreis Osterholz informieren.
 
Die Allgemeinverfügung, eine Übersicht zur Überwachungszone und weitere Hinweise sind auf der Internetseite unter www.landkreis-osterholz.de/gefluegelpest zu finden.", - "parameter": [ - { - "valueName": "sender_langname", - "value": "Landkreis Osterholz" - }, - { - "valueName": "PHGEM", - "value": "740+10,770,792,817,100001" - }, - { - "valueName": "GRID", - "value": "101346,101954+7,102566+9,103177+13,103774,103790+13,104387+1,104403+13,105000+1,105016+15,105612+2,105630+15,106225+2,106241+18,106838+2,106853+18,107451+1,107464+22,108064+9,108075+23,108677+34,109290+34,109903+35,110516+35,111129+35,111742+35,112355,112357+34,112971+33,113587+30,114200+30,114814,114818+26,115432,115436+22,116050+21,116669+15,117283+5,117290+7,117897+3,117904+6,500001" - } - ], - "area": [ - { - "areaDesc": "Axstedt, Gnarrenburg, Grasberg, Hagen im Bremischen, Hambergen, Hepstedt, Holste, Lilienthal, Lübberstedt, Osterholz-Scharmbeck, Ritterhude, Schwanewede, Vollersode, Worpswede", - "geocode": [ - { - "valueName": "AreaId", - "value": "0" - } - ] - } - ] - } - ] - } -} diff --git a/tests/components/nina/fixtures/sample_warnings.json b/tests/components/nina/fixtures/sample_warnings.json deleted file mode 100644 index 83759a5e0e8..00000000000 --- a/tests/components/nina/fixtures/sample_warnings.json +++ /dev/null @@ -1,89 +0,0 @@ -[ - { - "id": "mow.DE-BW-S-SE018-20211102-18-001", - "payload": { - "version": 1, - "type": "ALERT", - "id": "mow.DE-BW-S-SE018-20211102-18-001", - "hash": "cae97b1c11bde900017305f681904ad5a6e8fd1c841241ced524b83eaa3522f4", - "data": { - "headline": "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen", - "provider": "MOWAS", - "severity": "Minor", - "msgType": "Update", - "transKeys": { "event": "BBK-EVC-040" }, - "area": { "type": "ZGEM", "data": "9956+1102,100001" } - } - }, - "i18nTitle": { - "de": "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen" - }, - "sent": "2021-11-02T20:07:16+01:00" - }, - { - "id": "mow.DE-NW-BN-SE030-20201014-30-000", - "payload": { - "version": 1, - "type": "ALERT", - "id": "mow.DE-NW-BN-SE030-20201014-30-000", - "hash": "551db820a43be7e4f39283e1dfb71b212cd520c3ee478d44f43519e9c48fde4c", - "data": { - "headline": "Ausfall Notruf 112", - "provider": "MOWAS", - "severity": "Minor", - "msgType": "Update", - "transKeys": { "event": "BBK-EVC-040" }, - "area": { "type": "ZGEM", "data": "1+11057,100001" } - } - }, - "i18nTitle": { "de": "Ausfall Notruf 112" }, - "onset": "2021-11-01T05:20:00+01:00", - "sent": "2021-10-11T05:20:00+01:00", - "expires": "3021-11-22T05:19:00+01:00" - }, - { - "id": "mow.DE-NW-BN-SE030-20201014-30-011", - "payload": { - "version": 1, - "type": "ALERT", - "id": "mow.DE-NW-BN-SE030-20201014-30-011", - "hash": "551db820a43be7e4f39283e1dfb71b212cd520c3ee478d44f43519e9c42fde1c", - "data": { - "headline": "Ausfall Notruf 112", - "provider": "MOWAS", - "severity": "Minor", - "msgType": "Update", - "transKeys": { "event": "BBK-EVC-040" }, - "area": { "type": "ZGEM", "data": "1+11057,100001" } - } - }, - "i18nTitle": { "de": "Ausfall Notruf 112" }, - "onset": "2021-11-01T05:20:00+01:00", - "sent": "2021-10-11T05:21:00+01:00", - "expires": "3021-11-22T05:19:00+01:00" - }, - { - "id": "biw.BIWAPP-69634", - "payload": { - "version": 2, - "type": "ALERT", - "id": "biw.BIWAPP-69634", - "hash": "fdbafb6b164f549ff60b9adfa5b1c707069cdd178bf55f025066f319451660ad", - "data": { - "headline": "Geflügelpest im Landkreis Cuxhaven - Teile des Landkreises Osterholz zur Überwachungszone erklärt", - "provider": "BIWAPP", - "severity": "Minor", - "msgType": "Alert", - "area": { - "type": "GRID", - "data": "101346,101954+7,102566+9,103177+13,103774,103790+13,104387+1,104403+13,105000+1,105016+15,105612+2,105630+15,106225+2,106241+18,106838+2,106853+18,107451+1,107464+22,108064+9,108075+23,108677+34,109290+34,109903+35,110516+35,111129+35,111742+35,112355,112357+34,112971+33,113587+30,114200+30,114814,114818+26,115432,115436+22,116050+21,116669+15,117283+5,117290+7,117897+3,117904+6,500001" - } - } - }, - "i18nTitle": { - "de": "Geflügelpest im Landkreis Cuxhaven - Teile des Landkreises Osterholz zur Überwachungszone erklärt" - }, - "sent": "1999-08-07T10:59:00+02:00", - "expires": "2002-08-07T10:59:00+02:00" - } -] diff --git a/tests/components/nina/fixtures/warnings.json b/tests/components/nina/fixtures/warnings.json new file mode 100644 index 00000000000..2e3a9f4ecea --- /dev/null +++ b/tests/components/nina/fixtures/warnings.json @@ -0,0 +1,64 @@ +[ + { + "id": "mow.DE-BW-S-SE018-20211102-18-001", + "headline": "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen", + "severity": "Minor", + "description": "Die Zahl der mit dem Corona-Virus infizierten Menschen steigt gegenwärtig stark an. Es wächst daher die Gefahr einer weiteren Verbreitung der Infektion und - je nach Einzelfall - auch von schweren Erkrankungen.", + "sender": null, + "affected_areas": [ + "Bundesland: Freie Hansestadt Bremen, Land Berlin, Land Hessen, Land Nordrhein-Westfalen, Land Brandenburg, Freistaat Bayern, Land Mecklenburg-Vorpommern, Land Rheinland-Pfalz, Freistaat Sachsen, Land Schleswig-Holstein, Freie und Hansestadt Hamburg, Freistaat Thüringen, Land Niedersachsen, Land Saarland, Land Sachsen-Anhalt, Land Baden-Württemberg" + ], + "recommended_actions": ["Waschen sich regelmäßig und gründlich die Hände."], + "web": null, + "sent": "2021-11-02T20:07:16+01:00", + "start": null, + "expires": null + }, + { + "id": "mow.DE-NW-BN-SE030-20201014-30-000", + "headline": "Ausfall Notruf 112", + "severity": "Minor", + "description": "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.", + "sender": "Deutscher Wetterdienst", + "affected_areas": [ + "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere." + ], + "recommended_actions": [], + "web": "https://www.wettergefahren.de", + "sent": "2021-10-11T05:20:00+01:00", + "start": "2021-11-01T05:20:00+01:00", + "expires": "3021-11-22T05:19:00+01:00" + }, + { + "id": "mow.DE-NW-BN-SE030-20201014-30-011", + "headline": "Ausfall Notruf 112", + "severity": "Minor", + "description": "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.", + "sender": "Deutscher Wetterdienst", + "affected_areas": [ + "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere." + ], + "recommended_actions": [ + "ACHTUNG! Hinweis auf mögliche Gefahren: Es können zum Beispiel einzelne Äste herabstürzen. Achten Sie besonders auf herabfallende Gegenstände." + ], + "web": "https://www.wettergefahren.de", + "sent": "2021-10-11T05:21:00+01:00", + "start": "2021-11-01T05:20:00+01:00", + "expires": "3021-11-22T05:19:00+01:00" + }, + { + "id": "biw.BIWAPP-69634", + "headline": "Geflügelpest im Landkreis Cuxhaven - Teile des Landkreises Osterholz zur Überwachungszone erklärt", + "severity": "Minor", + "description": "In Beverstedt im Landkreis Cuxhaven ist am 20. Juli 2022 in einer Geflügelhaltung der Ausbruch der Geflügelpest (Vogelgrippe, Aviäre Influenza) amtlich festgestellt worden. Durch die geografische Nähe des Ausbruchsbetriebes zum Gebiet des Landkreises Osterholz musste das Veterinäramt des Landkreises zum Schutz vor einer Ausbreitung der Geflügelpest auch für sein Gebiet ein Restriktionsgebiet festlegen. Rund um den Ausbruchsort wurde eine Überwachungszone ausgewiesen. Eine entsprechende Tierseuchenbehördliche Allgemeinverfügung wurde vom Landkreis Osterholz erlassen und tritt am 23.07.2022 in Kraft.
 
Die Überwachungszone mit einem Radius von mindestens zehn Kilometern um den Ausbruchsbetrieb erstreckt sich im Landkreis Osterholz innerhalb der Samtgemeinde Hambergen auf die Mitgliedsgemeinden Axstedt, Holste und Lübberstedt. Die vorgenannten Gemeinden sind vollständig zur Überwachungszone erklärt worden. Der genaue Grenzverlauf des Gebietes kann auch der interaktiven Karte im Internet entnommen werden.
 
In der Überwachungszone liegen im Landkreis Osterholz rund 70 Geflügelhaltungen mit einem Gesamtbestand von rund 1.800 Tieren. Sie alle unterliegen mit der Allgemeinverfügung der sogenannten amtlichen Beobachtung. Für die Betriebe sind die Biosicherheitsmaßnahmen einzuhalten. Dazu zählen insbesondere Hygienemaßnahmen im laufenden Betrieb und eine ordnungsgemäße Schadnagerbekämpfung.
 
Das Verbringen von Vögeln, Fleisch von Geflügel, Eiern und sonstige Nebenprodukte von Geflügel in und aus Betrieben in der Überwachungszone ist verboten. Auch Geflügeltransporte sind in der Überwachungszone verboten. Jeder Verdacht der Erkrankung auf Geflügelpest ist zudem dem Veterinäramt des Landkreises Osterholz unter der E-Mail-Adresse veterinaeramt@landkreis-osterholz.de sofort zu melden. Alle Hinweise, die innerhalb der Überwachungszone zu beachten sind, sind unter www.landkreis-osterholz.de/gefluegelpest zusammengefasst dargestellt.
 
Die Veterinärbehörde weist zudem darauf hin, dass sämtliche Geflügelhaltungen – Hühner, Enten, Gänse, Fasane, Perlhühner, Rebhühner, Truthühner, Wachteln oder Laufvögel – der zuständigen Behörde angezeigt werden müssen. Wer dies bisher noch nicht gemacht hat und über keine Registriernummer für seinen Geflügelbestand verfügt, sollte die Meldung über das Veterinäramt umgehend nachholen.
 
Das Beobachtungsgebiet kann frühestens 30 Tage nach der Grobreinigung des Ausbruchsbetriebes wieder aufgehoben werden. Hierüber wird der Landkreis Osterholz informieren.
 
Die Allgemeinverfügung, eine Übersicht zur Überwachungszone und weitere Hinweise sind auf der Internetseite unter www.landkreis-osterholz.de/gefluegelpest zu finden.", + "sender": null, + "affected_areas": [ + "Axstedt, Gnarrenburg, Grasberg, Hagen im Bremischen, Hambergen, Hepstedt, Holste, Lilienthal, Lübberstedt, Osterholz-Scharmbeck, Ritterhude, Schwanewede, Vollersode, Worpswede" + ], + "recommended_actions": [], + "web": null, + "sent": "1999-08-07T10:59:00+02:00", + "start": null, + "expires": "2002-08-07T10:59:00+02:00" + } +] diff --git a/tests/components/nina/snapshots/test_binary_sensor.ambr b/tests/components/nina/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..a00e9d32fd4 --- /dev/null +++ b/tests/components/nina/snapshots/test_binary_sensor.ambr @@ -0,0 +1,262 @@ +# serializer version: 1 +# name: test_sensors[binary_sensor.nina_warning_aach_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.nina_warning_aach_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Warning: Aach 1', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Warning: Aach 1', + 'platform': 'nina', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '095760000000-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'affected_areas': 'Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere.', + 'description': 'Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.', + 'device_class': 'safety', + 'expires': '3021-11-22T05:19:00+01:00', + 'friendly_name': 'NINA Warning: Aach 1', + 'headline': 'Ausfall Notruf 112', + 'id': 'mow.DE-NW-BN-SE030-20201014-30-000', + 'recommended_actions': '', + 'sender': 'Deutscher Wetterdienst', + 'sent': '2021-10-11T05:20:00+01:00', + 'severity': 'Minor', + 'start': '2021-11-01T05:20:00+01:00', + 'web': 'https://www.wettergefahren.de', + }), + 'context': , + 'entity_id': 'binary_sensor.nina_warning_aach_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.nina_warning_aach_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Warning: Aach 2', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Warning: Aach 2', + 'platform': 'nina', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '095760000000-2', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'safety', + 'friendly_name': 'NINA Warning: Aach 2', + }), + 'context': , + 'entity_id': 'binary_sensor.nina_warning_aach_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.nina_warning_aach_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Warning: Aach 3', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Warning: Aach 3', + 'platform': 'nina', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '095760000000-3', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'safety', + 'friendly_name': 'NINA Warning: Aach 3', + }), + 'context': , + 'entity_id': 'binary_sensor.nina_warning_aach_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.nina_warning_aach_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Warning: Aach 4', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Warning: Aach 4', + 'platform': 'nina', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '095760000000-4', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'safety', + 'friendly_name': 'NINA Warning: Aach 4', + }), + 'context': , + 'entity_id': 'binary_sensor.nina_warning_aach_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_5-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.nina_warning_aach_5', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Warning: Aach 5', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Warning: Aach 5', + 'platform': 'nina', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '095760000000-5', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[binary_sensor.nina_warning_aach_5-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'safety', + 'friendly_name': 'NINA Warning: Aach 5', + }), + 'context': , + 'entity_id': 'binary_sensor.nina_warning_aach_5', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/nina/snapshots/test_diagnostics.ambr b/tests/components/nina/snapshots/test_diagnostics.ambr index 331323ff76c..beeba164e02 100644 --- a/tests/components/nina/snapshots/test_diagnostics.ambr +++ b/tests/components/nina/snapshots/test_diagnostics.ambr @@ -2,7 +2,7 @@ # name: test_diagnostics dict({ 'data': dict({ - '083350000000': list([ + '095760000000': list([ dict({ 'affected_areas': 'Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere.', 'description': 'Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden.', @@ -25,7 +25,7 @@ 'id': 'biw.BIWAPP-69634', 'is_valid': False, 'recommended_actions': '', - 'sender': '', + 'sender': None, 'sent': '1999-08-07T10:59:00+02:00', 'severity': 'Minor', 'start': '', @@ -34,12 +34,16 @@ ]), }), 'entry_data': dict({ + '_a_to_d': list([ + '095760000000_0', + '095760000000_1', + ]), 'filters': dict({ 'area_filter': '.*', 'headline_filter': '.*corona.*', }), 'regions': dict({ - '083350000000': 'Aach, Stadt', + '095760000000': 'Aach', }), 'slots': 5, }), diff --git a/tests/components/nina/test_binary_sensor.py b/tests/components/nina/test_binary_sensor.py index daaabade423..ce66142666a 100644 --- a/tests/components/nina/test_binary_sensor.py +++ b/tests/components/nina/test_binary_sensor.py @@ -3,375 +3,142 @@ from __future__ import annotations from typing import Any -from unittest.mock import patch +from unittest.mock import AsyncMock + +from syrupy.assertion import SnapshotAssertion -from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.nina.const import ( - ATTR_AFFECTED_AREAS, - ATTR_DESCRIPTION, - ATTR_EXPIRES, ATTR_HEADLINE, - ATTR_ID, - ATTR_RECOMMENDED_ACTIONS, - ATTR_SENDER, - ATTR_SENT, - ATTR_SEVERITY, - ATTR_START, - ATTR_WEB, + CONF_AREA_FILTER, + CONF_FILTERS, + CONF_HEADLINE_FILTER, + CONF_MESSAGE_SLOTS, + CONF_REGIONS, DOMAIN, ) -from homeassistant.config_entries import ConfigEntryState from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from . import mocked_request_function +from . import setup_platform -from tests.common import MockConfigEntry - -ENTRY_DATA: dict[str, Any] = { - "slots": 5, - "regions": {"083350000000": "Aach, Stadt"}, - "filters": { - "headline_filter": ".*corona.*", - "area_filter": ".*", - }, -} +from tests.common import MockConfigEntry, snapshot_platform ENTRY_DATA_NO_CORONA: dict[str, Any] = { - "slots": 5, - "regions": {"083350000000": "Aach, Stadt"}, - "filters": { - "headline_filter": "/(?!)/", - "area_filter": ".*", + CONF_MESSAGE_SLOTS: 5, + CONF_REGIONS: {"083350000000": "Aach, Stadt"}, + CONF_FILTERS: { + CONF_HEADLINE_FILTER: "/(?!)/", + CONF_AREA_FILTER: ".*", }, } -ENTRY_DATA_NO_AREA: dict[str, Any] = { - "slots": 5, - "regions": {"083350000000": "Aach, Stadt"}, - "filters": { - "headline_filter": "/(?!)/", - "area_filter": ".*nagold.*", +ENTRY_DATA_SPECIFIC_AREA: dict[str, Any] = { + CONF_MESSAGE_SLOTS: 5, + CONF_REGIONS: {"083350000000": "Aach, Stadt"}, + CONF_FILTERS: { + CONF_HEADLINE_FILTER: "/(?!)/", + CONF_AREA_FILTER: ".*nagold.*", }, } -async def test_sensors(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None: +async def test_sensors( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: """Test the creation and values of the NINA sensors.""" - - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - conf_entry: MockConfigEntry = MockConfigEntry( - domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=1, minor_version=3 - ) - conf_entry.add_to_hass(hass) - - await hass.config_entries.async_setup(conf_entry.entry_id) - await hass.async_block_till_done() - - assert conf_entry.state is ConfigEntryState.LOADED - - state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1") - entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1") - - assert state_w1.state == STATE_ON - assert state_w1.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112" - assert ( - state_w1.attributes.get(ATTR_DESCRIPTION) - == "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden." - ) - assert state_w1.attributes.get(ATTR_SENDER) == "Deutscher Wetterdienst" - assert state_w1.attributes.get(ATTR_SEVERITY) == "Minor" - assert state_w1.attributes.get(ATTR_RECOMMENDED_ACTIONS) == "" - assert state_w1.attributes.get(ATTR_WEB) == "https://www.wettergefahren.de" - assert ( - state_w1.attributes.get(ATTR_AFFECTED_AREAS) - == "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere." - ) - assert state_w1.attributes.get(ATTR_ID) == "mow.DE-NW-BN-SE030-20201014-30-000" - assert state_w1.attributes.get(ATTR_SENT) == "2021-10-11T05:20:00+01:00" - assert state_w1.attributes.get(ATTR_START) == "2021-11-01T05:20:00+01:00" - assert state_w1.attributes.get(ATTR_EXPIRES) == "3021-11-22T05:19:00+01:00" - - assert entry_w1.unique_id == "083350000000-1" - assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2") - entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2") - - assert state_w2.state == STATE_OFF - assert state_w2.attributes.get(ATTR_HEADLINE) is None - assert state_w2.attributes.get(ATTR_DESCRIPTION) is None - assert state_w2.attributes.get(ATTR_SENDER) is None - assert state_w2.attributes.get(ATTR_SEVERITY) is None - assert state_w2.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w2.attributes.get(ATTR_WEB) is None - assert state_w2.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w2.attributes.get(ATTR_ID) is None - assert state_w2.attributes.get(ATTR_SENT) is None - assert state_w2.attributes.get(ATTR_START) is None - assert state_w2.attributes.get(ATTR_EXPIRES) is None - - assert entry_w2.unique_id == "083350000000-2" - assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3") - entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3") - - assert state_w3.state == STATE_OFF - assert state_w3.attributes.get(ATTR_HEADLINE) is None - assert state_w3.attributes.get(ATTR_DESCRIPTION) is None - assert state_w3.attributes.get(ATTR_SENDER) is None - assert state_w3.attributes.get(ATTR_SEVERITY) is None - assert state_w3.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w3.attributes.get(ATTR_WEB) is None - assert state_w3.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w3.attributes.get(ATTR_ID) is None - assert state_w3.attributes.get(ATTR_SENT) is None - assert state_w3.attributes.get(ATTR_START) is None - assert state_w3.attributes.get(ATTR_EXPIRES) is None - - assert entry_w3.unique_id == "083350000000-3" - assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4") - entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4") - - assert state_w4.state == STATE_OFF - assert state_w4.attributes.get(ATTR_HEADLINE) is None - assert state_w4.attributes.get(ATTR_DESCRIPTION) is None - assert state_w4.attributes.get(ATTR_SENDER) is None - assert state_w4.attributes.get(ATTR_SEVERITY) is None - assert state_w4.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w4.attributes.get(ATTR_WEB) is None - assert state_w4.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w4.attributes.get(ATTR_ID) is None - assert state_w4.attributes.get(ATTR_SENT) is None - assert state_w4.attributes.get(ATTR_START) is None - assert state_w4.attributes.get(ATTR_EXPIRES) is None - - assert entry_w4.unique_id == "083350000000-4" - assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5") - entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5") - - assert state_w5.state == STATE_OFF - assert state_w5.attributes.get(ATTR_HEADLINE) is None - assert state_w5.attributes.get(ATTR_DESCRIPTION) is None - assert state_w5.attributes.get(ATTR_SENDER) is None - assert state_w5.attributes.get(ATTR_SEVERITY) is None - assert state_w5.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w5.attributes.get(ATTR_WEB) is None - assert state_w5.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w5.attributes.get(ATTR_ID) is None - assert state_w5.attributes.get(ATTR_SENT) is None - assert state_w5.attributes.get(ATTR_START) is None - assert state_w5.attributes.get(ATTR_EXPIRES) is None - - assert entry_w5.unique_id == "083350000000-5" - assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) async def test_sensors_without_corona_filter( - hass: HomeAssistant, entity_registry: er.EntityRegistry + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test the creation and values of the NINA sensors without the corona filter.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - conf_entry: MockConfigEntry = MockConfigEntry( - domain=DOMAIN, - title="NINA", - data=ENTRY_DATA_NO_CORONA, - version=1, - minor_version=3, - ) - conf_entry.add_to_hass(hass) + conf_entry: MockConfigEntry = MockConfigEntry( + domain=DOMAIN, + title="NINA", + data=ENTRY_DATA_NO_CORONA, + version=1, + minor_version=3, + ) + conf_entry.add_to_hass(hass) - await hass.config_entries.async_setup(conf_entry.entry_id) - await hass.async_block_till_done() + await setup_platform(hass, conf_entry, mock_nina_class, nina_warnings) - assert conf_entry.state is ConfigEntryState.LOADED + state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1") - state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1") - entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1") + assert state_w1.state == STATE_ON + assert ( + state_w1.attributes.get(ATTR_HEADLINE) + == "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen" + ) - assert state_w1.state == STATE_ON - assert ( - state_w1.attributes.get(ATTR_HEADLINE) - == "Corona-Verordnung des Landes: Warnstufe durch Landesgesundheitsamt ausgerufen" - ) - assert ( - state_w1.attributes.get(ATTR_DESCRIPTION) - == "Die Zahl der mit dem Corona-Virus infizierten Menschen steigt gegenwärtig stark an. Es wächst daher die Gefahr einer weiteren Verbreitung der Infektion und - je nach Einzelfall - auch von schweren Erkrankungen." - ) - assert state_w1.attributes.get(ATTR_SENDER) == "" - assert state_w1.attributes.get(ATTR_SEVERITY) == "Minor" - assert ( - state_w1.attributes.get(ATTR_RECOMMENDED_ACTIONS) - == "Waschen sich regelmäßig und gründlich die Hände." - ) - assert state_w1.attributes.get(ATTR_WEB) == "" - assert ( - state_w1.attributes.get(ATTR_AFFECTED_AREAS) - == "Bundesland: Freie Hansestadt Bremen, Land Berlin, Land Hessen, Land Nordrhein-Westfalen, Land Brandenburg, Freistaat Bayern, Land Mecklenburg-Vorpommern, Land Rheinland-Pfalz, Freistaat Sachsen, Land Schleswig-Holstein, Freie und Hansestadt Hamburg, Freistaat Thüringen, Land Niedersachsen, Land Saarland, Land Sachsen-Anhalt, Land Baden-Württemberg" - ) - assert state_w1.attributes.get(ATTR_ID) == "mow.DE-BW-S-SE018-20211102-18-001" - assert state_w1.attributes.get(ATTR_SENT) == "2021-11-02T20:07:16+01:00" - assert state_w1.attributes.get(ATTR_START) == "" - assert state_w1.attributes.get(ATTR_EXPIRES) == "" + state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2") - assert entry_w1.unique_id == "083350000000-1" - assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + assert state_w2.state == STATE_ON + assert state_w2.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112" - state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2") - entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2") + state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3") - assert state_w2.state == STATE_ON - assert state_w2.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112" - assert ( - state_w2.attributes.get(ATTR_DESCRIPTION) - == "Es treten Sturmböen mit Geschwindigkeiten zwischen 70 km/h (20m/s, 38kn, Bft 8) und 85 km/h (24m/s, 47kn, Bft 9) aus westlicher Richtung auf. In Schauernähe sowie in exponierten Lagen muss mit schweren Sturmböen bis 90 km/h (25m/s, 48kn, Bft 10) gerechnet werden." - ) - assert ( - state_w2.attributes.get(ATTR_AFFECTED_AREAS) - == "Gemeinde Oberreichenbach, Gemeinde Neuweiler, Stadt Nagold, Stadt Neubulach, Gemeinde Schömberg, Gemeinde Simmersfeld, Gemeinde Simmozheim, Gemeinde Rohrdorf, Gemeinde Ostelsheim, Gemeinde Ebhausen, Gemeinde Egenhausen, Gemeinde Dobel, Stadt Bad Liebenzell, Stadt Solingen, Stadt Haiterbach, Stadt Bad Herrenalb, Gemeinde Höfen an der Enz, Gemeinde Gechingen, Gemeinde Enzklösterle, Gemeinde Gutach (Schwarzwaldbahn) und 3392 weitere." - ) - assert state_w2.attributes.get(ATTR_SENDER) == "Deutscher Wetterdienst" - assert state_w2.attributes.get(ATTR_SEVERITY) == "Minor" - assert state_w2.attributes.get(ATTR_RECOMMENDED_ACTIONS) == "" - assert state_w2.attributes.get(ATTR_WEB) == "https://www.wettergefahren.de" - assert state_w2.attributes.get(ATTR_ID) == "mow.DE-NW-BN-SE030-20201014-30-000" - assert state_w2.attributes.get(ATTR_SENT) == "2021-10-11T05:20:00+01:00" - assert state_w2.attributes.get(ATTR_START) == "2021-11-01T05:20:00+01:00" - assert state_w2.attributes.get(ATTR_EXPIRES) == "3021-11-22T05:19:00+01:00" + assert state_w3.state == STATE_OFF - assert entry_w2.unique_id == "083350000000-2" - assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4") - state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3") - entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3") + assert state_w4.state == STATE_OFF - assert state_w3.state == STATE_OFF - assert state_w3.attributes.get(ATTR_HEADLINE) is None - assert state_w3.attributes.get(ATTR_DESCRIPTION) is None - assert state_w3.attributes.get(ATTR_SENDER) is None - assert state_w3.attributes.get(ATTR_SEVERITY) is None - assert state_w3.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w3.attributes.get(ATTR_WEB) is None - assert state_w3.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w3.attributes.get(ATTR_ID) is None - assert state_w3.attributes.get(ATTR_SENT) is None - assert state_w3.attributes.get(ATTR_START) is None - assert state_w3.attributes.get(ATTR_EXPIRES) is None + state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5") - assert entry_w3.unique_id == "083350000000-3" - assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4") - entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4") - - assert state_w4.state == STATE_OFF - assert state_w4.attributes.get(ATTR_HEADLINE) is None - assert state_w4.attributes.get(ATTR_DESCRIPTION) is None - assert state_w4.attributes.get(ATTR_SENDER) is None - assert state_w4.attributes.get(ATTR_SEVERITY) is None - assert state_w4.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w4.attributes.get(ATTR_WEB) is None - assert state_w4.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w4.attributes.get(ATTR_ID) is None - assert state_w4.attributes.get(ATTR_SENT) is None - assert state_w4.attributes.get(ATTR_START) is None - assert state_w4.attributes.get(ATTR_EXPIRES) is None - - assert entry_w4.unique_id == "083350000000-4" - assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5") - entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5") - - assert state_w5.state == STATE_OFF - assert state_w5.attributes.get(ATTR_HEADLINE) is None - assert state_w5.attributes.get(ATTR_DESCRIPTION) is None - assert state_w5.attributes.get(ATTR_SENDER) is None - assert state_w5.attributes.get(ATTR_SEVERITY) is None - assert state_w5.attributes.get(ATTR_RECOMMENDED_ACTIONS) is None - assert state_w5.attributes.get(ATTR_WEB) is None - assert state_w5.attributes.get(ATTR_AFFECTED_AREAS) is None - assert state_w5.attributes.get(ATTR_ID) is None - assert state_w5.attributes.get(ATTR_SENT) is None - assert state_w5.attributes.get(ATTR_START) is None - assert state_w5.attributes.get(ATTR_EXPIRES) is None - - assert entry_w5.unique_id == "083350000000-5" - assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + assert state_w5.state == STATE_OFF async def test_sensors_with_area_filter( - hass: HomeAssistant, entity_registry: er.EntityRegistry + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: - """Test the creation and values of the NINA sensors with an area filter.""" + """Test the creation and values of the NINA sensors with a restrictive area filter.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - conf_entry: MockConfigEntry = MockConfigEntry( - domain=DOMAIN, - title="NINA", - data=ENTRY_DATA_NO_AREA, - version=1, - minor_version=3, - ) - conf_entry.add_to_hass(hass) + conf_entry: MockConfigEntry = MockConfigEntry( + domain=DOMAIN, + title="NINA", + data=ENTRY_DATA_SPECIFIC_AREA, + version=1, + minor_version=3, + ) + conf_entry.add_to_hass(hass) - await hass.config_entries.async_setup(conf_entry.entry_id) - await hass.async_block_till_done() + await setup_platform(hass, conf_entry, mock_nina_class, nina_warnings) - assert conf_entry.state is ConfigEntryState.LOADED + state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1") - state_w1 = hass.states.get("binary_sensor.nina_warning_aach_stadt_1") - entry_w1 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_1") + assert state_w1.state == STATE_ON + assert state_w1.attributes.get(ATTR_HEADLINE) == "Ausfall Notruf 112" - assert state_w1.state == STATE_ON + state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2") - assert entry_w1.unique_id == "083350000000-1" - assert state_w1.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + assert state_w2.state == STATE_OFF - state_w2 = hass.states.get("binary_sensor.nina_warning_aach_stadt_2") - entry_w2 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_2") + state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3") - assert state_w2.state == STATE_OFF + assert state_w3.state == STATE_OFF - assert entry_w2.unique_id == "083350000000-2" - assert state_w2.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4") - state_w3 = hass.states.get("binary_sensor.nina_warning_aach_stadt_3") - entry_w3 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_3") + assert state_w4.state == STATE_OFF - assert state_w3.state == STATE_OFF + state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5") - assert entry_w3.unique_id == "083350000000-3" - assert state_w3.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w4 = hass.states.get("binary_sensor.nina_warning_aach_stadt_4") - entry_w4 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_4") - - assert state_w4.state == STATE_OFF - - assert entry_w4.unique_id == "083350000000-4" - assert state_w4.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY - - state_w5 = hass.states.get("binary_sensor.nina_warning_aach_stadt_5") - entry_w5 = entity_registry.async_get("binary_sensor.nina_warning_aach_stadt_5") - - assert state_w5.state == STATE_OFF - - assert entry_w5.unique_id == "083350000000-5" - assert state_w5.attributes.get("device_class") == BinarySensorDeviceClass.SAFETY + assert state_w5.state == STATE_OFF diff --git a/tests/components/nina/test_config_flow.py b/tests/components/nina/test_config_flow.py index b9b1e11f0db..4d67ec1da80 100644 --- a/tests/components/nina/test_config_flow.py +++ b/tests/components/nina/test_config_flow.py @@ -3,9 +3,8 @@ from __future__ import annotations from copy import deepcopy -import json from typing import Any -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock from pynina import ApiError @@ -28,14 +27,10 @@ from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import entity_registry as er -from . import mocked_request_function -from .const import DUMMY_CONFIG_ENTRY, DUMMY_USER_INPUT +from . import setup_platform +from .const import DUMMY_USER_INPUT -from tests.common import MockConfigEntry, load_fixture - -DUMMY_RESPONSE_REGIONS: dict[str, Any] = json.loads( - load_fixture("sample_regions.json", "nina") -) +from tests.common import MockConfigEntry def assert_dummy_entry_created(result: dict[str, Any]) -> None: @@ -51,297 +46,267 @@ def assert_dummy_entry_created(result: dict[str, Any]) -> None: assert result["minor_version"] == 3 -async def test_step_user_connection_error(hass: HomeAssistant) -> None: +async def test_step_user_connection_error( + hass: HomeAssistant, mock_nina_class: AsyncMock +) -> None: """Test starting a flow by user but no connection.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - side_effect=ApiError("Could not connect to Api"), - ): - result: dict[str, Any] = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER} - ) + mock_nina_class.get_all_regional_codes.side_effect = ApiError( + "Could not connect to Api" + ) - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "no_fetch" + result: dict[str, Any] = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "no_fetch" -async def test_step_user_unexpected_exception(hass: HomeAssistant) -> None: +async def test_step_user_unexpected_exception( + hass: HomeAssistant, mock_nina_class: AsyncMock +) -> None: """Test starting a flow by user but with an unexpected exception.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - side_effect=Exception("DUMMY"), - ): - result: dict[str, Any] = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER} - ) + mock_nina_class.get_all_regional_codes.side_effect = Exception("DUMMY") - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "unknown" + result: dict[str, Any] = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "unknown" -async def test_step_user(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None: +async def test_step_user( + hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_nina_class: AsyncMock +) -> None: """Test starting a flow by user with valid values.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - result: dict[str, Any] = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER} - ) + result: dict[str, Any] = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input=deepcopy(DUMMY_USER_INPUT), - ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=deepcopy(DUMMY_USER_INPUT), + ) - assert_dummy_entry_created(result) + assert_dummy_entry_created(result) -async def test_step_user_no_selection(hass: HomeAssistant) -> None: +async def test_step_user_no_selection( + hass: HomeAssistant, mock_nina_class: AsyncMock +) -> None: """Test starting a flow by user with no selection.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - result: dict[str, Any] = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - data={CONF_FILTERS: {CONF_HEADLINE_FILTER: ""}}, - ) + result: dict[str, Any] = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_FILTERS: {CONF_HEADLINE_FILTER: ""}}, + ) - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "user" - assert result["errors"] == {"base": "no_selection"} + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + assert result["errors"] == {"base": "no_selection"} - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input=deepcopy(DUMMY_USER_INPUT), - ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=deepcopy(DUMMY_USER_INPUT), + ) - assert_dummy_entry_created(result) + assert_dummy_entry_created(result) async def test_step_user_already_configured( - hass: HomeAssistant, mock_config_entry: MockConfigEntry + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_nina_class: AsyncMock ) -> None: """Test starting a flow by user, but it was already configured.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER} - ) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "single_instance_allowed" + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "single_instance_allowed" async def test_options_flow_init( - hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test config flow options.""" - with ( - patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ), - ): - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) - result = await hass.config_entries.options.async_init( - mock_config_entry.entry_id - ) + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "init" + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" - result = await hass.config_entries.options.async_configure( - result["flow_id"], - user_input={ - CONST_REGION_A_TO_D: ["072350000000_1"], - CONST_REGION_E_TO_H: [], - CONST_REGION_I_TO_L: [], - CONST_REGION_M_TO_Q: [], - CONST_REGION_R_TO_U: [], - CONST_REGION_V_TO_Z: [], - CONF_FILTERS: { - CONF_HEADLINE_FILTER: ".*corona.*", - CONF_AREA_FILTER: ".*", - }, - }, - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["data"] == {} - - assert dict(mock_config_entry.data) == { - CONF_FILTERS: DUMMY_USER_INPUT[CONF_FILTERS], - CONF_MESSAGE_SLOTS: DUMMY_USER_INPUT[CONF_MESSAGE_SLOTS], + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ CONST_REGION_A_TO_D: ["072350000000_1"], CONST_REGION_E_TO_H: [], CONST_REGION_I_TO_L: [], CONST_REGION_M_TO_Q: [], CONST_REGION_R_TO_U: [], CONST_REGION_V_TO_Z: [], - CONF_REGIONS: { - "072350000000": "Damflos (Trier-Saarburg - Rheinland-Pfalz)" + CONF_FILTERS: { + CONF_HEADLINE_FILTER: ".*corona.*", + CONF_AREA_FILTER: ".*", }, - } + }, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == {} + + assert dict(mock_config_entry.data) == { + CONF_FILTERS: DUMMY_USER_INPUT[CONF_FILTERS], + CONF_MESSAGE_SLOTS: DUMMY_USER_INPUT[CONF_MESSAGE_SLOTS], + CONST_REGION_A_TO_D: ["072350000000_1"], + CONST_REGION_E_TO_H: [], + CONST_REGION_I_TO_L: [], + CONST_REGION_M_TO_Q: [], + CONST_REGION_R_TO_U: [], + CONST_REGION_V_TO_Z: [], + CONF_REGIONS: {"072350000000": "Damflos (Trier-Saarburg - Rheinland-Pfalz)"}, + } async def test_options_flow_with_no_selection( - hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test config flow options with no selection.""" - with ( - patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ), - ): - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) - result = await hass.config_entries.options.async_init( - mock_config_entry.entry_id - ) + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "init" + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" - result = await hass.config_entries.options.async_configure( - result["flow_id"], - user_input={ - CONST_REGION_A_TO_D: [], - CONST_REGION_E_TO_H: [], - CONST_REGION_I_TO_L: [], - CONST_REGION_M_TO_Q: [], - CONST_REGION_R_TO_U: [], - CONST_REGION_V_TO_Z: [], - CONF_FILTERS: {CONF_HEADLINE_FILTER: ""}, - }, - ) + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONST_REGION_A_TO_D: [], + CONST_REGION_E_TO_H: [], + CONST_REGION_I_TO_L: [], + CONST_REGION_M_TO_Q: [], + CONST_REGION_R_TO_U: [], + CONST_REGION_V_TO_Z: [], + CONF_FILTERS: {CONF_HEADLINE_FILTER: ""}, + }, + ) - assert result["type"] is FlowResultType.FORM - assert result["step_id"] == "init" - assert result["errors"] == {"base": "no_selection"} + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" + assert result["errors"] == {"base": "no_selection"} - result = await hass.config_entries.options.async_configure( - result["flow_id"], - user_input={ - CONST_REGION_A_TO_D: ["095760000000_0"], - CONST_REGION_E_TO_H: [], - CONST_REGION_I_TO_L: [], - CONST_REGION_M_TO_Q: [], - CONST_REGION_R_TO_U: [], - CONST_REGION_V_TO_Z: [], - CONF_FILTERS: { - CONF_HEADLINE_FILTER: ".*corona.*", - CONF_AREA_FILTER: ".*", - }, - }, - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["data"] == {} - - assert dict(mock_config_entry.data) == { - CONF_FILTERS: DUMMY_USER_INPUT[CONF_FILTERS], - CONF_MESSAGE_SLOTS: DUMMY_USER_INPUT[CONF_MESSAGE_SLOTS], + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ CONST_REGION_A_TO_D: ["095760000000_0"], CONST_REGION_E_TO_H: [], CONST_REGION_I_TO_L: [], CONST_REGION_M_TO_Q: [], CONST_REGION_R_TO_U: [], CONST_REGION_V_TO_Z: [], - CONF_REGIONS: {"095760000000": "Allersberg, M (Roth - Bayern)"}, - } + CONF_FILTERS: { + CONF_HEADLINE_FILTER: ".*corona.*", + CONF_AREA_FILTER: ".*", + }, + }, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == {} + + assert dict(mock_config_entry.data) == { + CONF_FILTERS: DUMMY_USER_INPUT[CONF_FILTERS], + CONF_MESSAGE_SLOTS: DUMMY_USER_INPUT[CONF_MESSAGE_SLOTS], + CONST_REGION_A_TO_D: ["095760000000_0"], + CONST_REGION_E_TO_H: [], + CONST_REGION_I_TO_L: [], + CONST_REGION_M_TO_Q: [], + CONST_REGION_R_TO_U: [], + CONST_REGION_V_TO_Z: [], + CONF_REGIONS: {"095760000000": "Allersberg, M (Roth - Bayern)"}, + } async def test_options_flow_connection_error( - hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test config flow options but no connection.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - side_effect=ApiError("Could not connect to Api"), - ): - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() + mock_nina_class.get_all_regional_codes.side_effect = ApiError( + "Could not connect to Api" + ) - result = await hass.config_entries.options.async_init( - mock_config_entry.entry_id - ) + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "no_fetch" + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "no_fetch" async def test_options_flow_unexpected_exception( - hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_config_entry: MockConfigEntry + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test config flow options but with an unexpected exception.""" - with ( - patch( - "pynina.baseApi.BaseAPI._makeRequest", - side_effect=Exception("DUMMY"), - ), - ): - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() + mock_nina_class.get_all_regional_codes.side_effect = Exception("DUMMY") - result = await hass.config_entries.options.async_init( - mock_config_entry.entry_id - ) + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "unknown" + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "unknown" async def test_options_flow_entity_removal( - hass: HomeAssistant, entity_registry: er.EntityRegistry + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test if old entities are removed.""" - config_entry = MockConfigEntry( - domain=DOMAIN, - title="NINA", - data=deepcopy(DUMMY_CONFIG_ENTRY) | {CONF_REGIONS: {"095760000000": "Aach"}}, - version=1, - minor_version=3, + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) + + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + + new_slot_count = 2 + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={ + CONF_MESSAGE_SLOTS: new_slot_count, + CONST_REGION_A_TO_D: ["095760000000"], + CONST_REGION_E_TO_H: [], + CONST_REGION_I_TO_L: [], + CONST_REGION_M_TO_Q: [], + CONST_REGION_R_TO_U: [], + CONST_REGION_V_TO_Z: [], + CONF_FILTERS: {}, + }, ) - config_entry.add_to_hass(hass) - with ( - patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ), - ): - await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() + assert result["type"] is FlowResultType.CREATE_ENTRY - result = await hass.config_entries.options.async_init(config_entry.entry_id) + entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) - result = await hass.config_entries.options.async_configure( - result["flow_id"], - user_input={ - CONF_MESSAGE_SLOTS: 2, - CONST_REGION_A_TO_D: ["072350000000", "095760000000"], - CONST_REGION_E_TO_H: [], - CONST_REGION_I_TO_L: [], - CONST_REGION_M_TO_Q: [], - CONST_REGION_R_TO_U: [], - CONST_REGION_V_TO_Z: [], - CONF_FILTERS: {}, - }, - ) - - assert result["type"] is FlowResultType.CREATE_ENTRY - - entries = er.async_entries_for_config_entry( - entity_registry, config_entry.entry_id - ) - - assert len(entries) == 2 + assert len(entries) == new_slot_count diff --git a/tests/components/nina/test_diagnostics.py b/tests/components/nina/test_diagnostics.py index 9a5538bacbb..96d0a3b6a8e 100644 --- a/tests/components/nina/test_diagnostics.py +++ b/tests/components/nina/test_diagnostics.py @@ -1,48 +1,30 @@ """Test the Nina diagnostics.""" -from typing import Any -from unittest.mock import patch +from unittest.mock import AsyncMock from syrupy.assertion import SnapshotAssertion -from homeassistant.components.nina.const import DOMAIN from homeassistant.core import HomeAssistant -from . import mocked_request_function +from . import setup_platform from tests.common import MockConfigEntry from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.typing import ClientSessionGenerator -ENTRY_DATA: dict[str, Any] = { - "slots": 5, - "regions": {"083350000000": "Aach, Stadt"}, - "filters": { - "headline_filter": ".*corona.*", - "area_filter": ".*", - }, -} - async def test_diagnostics( hass: HomeAssistant, hass_client: ClientSessionGenerator, snapshot: SnapshotAssertion, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], ) -> None: """Test diagnostics.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - config_entry: MockConfigEntry = MockConfigEntry( - domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=1, minor_version=3 - ) - - config_entry.add_to_hass(hass) - await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - assert ( - await get_diagnostics_for_config_entry(hass, hass_client, config_entry) - == snapshot - ) + await setup_platform(hass, mock_config_entry, mock_nina_class, nina_warnings) + assert ( + await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry) + == snapshot + ) diff --git a/tests/components/nina/test_init.py b/tests/components/nina/test_init.py index feba6110f3f..e6cb8cb8f3b 100644 --- a/tests/components/nina/test_init.py +++ b/tests/components/nina/test_init.py @@ -1,141 +1,119 @@ """Test the Nina init file.""" from typing import Any -from unittest.mock import patch +from unittest.mock import AsyncMock from pynina import ApiError -from homeassistant.components.nina.const import DOMAIN +from homeassistant.components.nina.const import ( + CONF_AREA_FILTER, + CONF_FILTER_CORONA, + CONF_FILTERS, + CONF_HEADLINE_FILTER, + CONF_MESSAGE_SLOTS, + CONF_REGIONS, + DOMAIN, +) from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant -from homeassistant.setup import async_setup_component -from . import mocked_request_function +from . import setup_platform from tests.common import MockConfigEntry ENTRY_DATA: dict[str, Any] = { - "slots": 5, - "regions": {"083350000000": "Aach, Stadt"}, - "filters": { - "headline_filter": ".*corona.*", - "area_filter": ".*", + CONF_MESSAGE_SLOTS: 5, + CONF_REGIONS: {"083350000000": "Aach, Stadt"}, + CONF_FILTERS: { + CONF_HEADLINE_FILTER: ".*corona.*", + CONF_AREA_FILTER: ".*", }, } -async def init_integration(hass: HomeAssistant) -> MockConfigEntry: - """Set up the NINA integration in Home Assistant.""" - - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - entry: MockConfigEntry = MockConfigEntry( - domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=1, minor_version=3 - ) - entry.add_to_hass(hass) - - assert await async_setup_component(hass, DOMAIN, {}) - await hass.async_block_till_done() - return entry - - -async def test_config_migration_from1_1(hass: HomeAssistant) -> None: +async def test_config_migration_from1_1( + hass: HomeAssistant, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: """Test the migration to a new configuration layout.""" old_entry_data: dict[str, Any] = { - "slots": 5, - "corona_filter": True, - "regions": {"083350000000": "Aach, Stadt"}, + CONF_MESSAGE_SLOTS: 5, + CONF_FILTER_CORONA: True, + CONF_REGIONS: {"083350000000": "Aach, Stadt"}, } old_conf_entry: MockConfigEntry = MockConfigEntry( domain=DOMAIN, title="NINA", data=old_entry_data, version=1 ) - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - old_conf_entry.add_to_hass(hass) + old_conf_entry.add_to_hass(hass) - await hass.config_entries.async_setup(old_conf_entry.entry_id) - await hass.async_block_till_done() + await setup_platform(hass, old_conf_entry, mock_nina_class, nina_warnings) - assert dict(old_conf_entry.data) == ENTRY_DATA - assert old_conf_entry.state is ConfigEntryState.LOADED - assert old_conf_entry.version == 1 - assert old_conf_entry.minor_version == 3 + assert dict(old_conf_entry.data) == ENTRY_DATA + assert old_conf_entry.state is ConfigEntryState.LOADED + assert old_conf_entry.version == 1 + assert old_conf_entry.minor_version == 3 -async def test_config_migration_from1_2(hass: HomeAssistant) -> None: +async def test_config_migration_from1_2( + hass: HomeAssistant, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: """Test the migration to a new configuration layout with sections.""" old_entry_data: dict[str, Any] = { - "slots": 5, - "headline_filter": ".*corona.*", - "area_filter": ".*", - "regions": {"083350000000": "Aach, Stadt"}, + CONF_MESSAGE_SLOTS: 5, + CONF_HEADLINE_FILTER: ".*corona.*", + CONF_AREA_FILTER: ".*", + CONF_REGIONS: {"083350000000": "Aach, Stadt"}, } old_conf_entry: MockConfigEntry = MockConfigEntry( domain=DOMAIN, title="NINA", data=old_entry_data, version=1, minor_version=2 ) - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - old_conf_entry.add_to_hass(hass) + old_conf_entry.add_to_hass(hass) - await hass.config_entries.async_setup(old_conf_entry.entry_id) - await hass.async_block_till_done() + await setup_platform(hass, old_conf_entry, mock_nina_class, nina_warnings) - assert dict(old_conf_entry.data) == ENTRY_DATA - assert old_conf_entry.state is ConfigEntryState.LOADED - assert old_conf_entry.version == 1 - assert old_conf_entry.minor_version == 3 + assert dict(old_conf_entry.data) == ENTRY_DATA + assert old_conf_entry.state is ConfigEntryState.LOADED + assert old_conf_entry.version == 1 + assert old_conf_entry.minor_version == 3 -async def test_config_migration_downgrade(hass: HomeAssistant) -> None: +async def test_config_migration_downgrade( + hass: HomeAssistant, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: """Test the migration to an old version.""" conf_entry: MockConfigEntry = MockConfigEntry( domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=2 ) - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - wraps=mocked_request_function, - ): - conf_entry.add_to_hass(hass) + conf_entry.add_to_hass(hass) - await hass.config_entries.async_setup(conf_entry.entry_id) - await hass.async_block_till_done() + await hass.config_entries.async_setup(conf_entry.entry_id) + await hass.async_block_till_done() - assert dict(conf_entry.data) == ENTRY_DATA - assert conf_entry.state is ConfigEntryState.MIGRATION_ERROR + assert dict(conf_entry.data) == ENTRY_DATA + assert conf_entry.state is ConfigEntryState.MIGRATION_ERROR -async def test_config_entry_not_ready(hass: HomeAssistant) -> None: - """Test the configuration entry.""" - entry: MockConfigEntry = await init_integration(hass) - - assert entry.state is ConfigEntryState.LOADED - - -async def test_sensors_connection_error(hass: HomeAssistant) -> None: +async def test_sensors_connection_error( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_nina_class: AsyncMock, + nina_warnings: list[Warning], +) -> None: """Test the creation and values of the NINA sensors with no connected.""" - with patch( - "pynina.baseApi.BaseAPI._makeRequest", - side_effect=ApiError("Could not connect to Api"), - ): - conf_entry: MockConfigEntry = MockConfigEntry( - domain=DOMAIN, title="NINA", data=ENTRY_DATA, version=1, minor_version=3 - ) + mock_nina_class.update.side_effect = ApiError("Could not connect to Api") - conf_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() - await hass.config_entries.async_setup(conf_entry.entry_id) - await hass.async_block_till_done() - - assert conf_entry.state is ConfigEntryState.SETUP_RETRY + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY diff --git a/tests/components/nintendo_parental_controls/snapshots/test_number.ambr b/tests/components/nintendo_parental_controls/snapshots/test_number.ambr index 6b9b4c01513..2e9aba5f1da 100644 --- a/tests/components/nintendo_parental_controls/snapshots/test_number.ambr +++ b/tests/components/nintendo_parental_controls/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max screentime today', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nintendo_parental_controls/snapshots/test_select.ambr b/tests/components/nintendo_parental_controls/snapshots/test_select.ambr index e85f89a7295..e00c58c62c0 100644 --- a/tests/components/nintendo_parental_controls/snapshots/test_select.ambr +++ b/tests/components/nintendo_parental_controls/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restriction mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nintendo_parental_controls/snapshots/test_sensor.ambr b/tests/components/nintendo_parental_controls/snapshots/test_sensor.ambr index 25afbf4442e..c36be59dbcf 100644 --- a/tests/components/nintendo_parental_controls/snapshots/test_sensor.ambr +++ b/tests/components/nintendo_parental_controls/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extended screen time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Screen time remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Used screen time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/nintendo_parental_controls/snapshots/test_switch.ambr b/tests/components/nintendo_parental_controls/snapshots/test_switch.ambr index e93510668be..3b183f5186b 100644 --- a/tests/components/nintendo_parental_controls/snapshots/test_switch.ambr +++ b/tests/components/nintendo_parental_controls/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Suspend software', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/nintendo_parental_controls/snapshots/test_time.ambr b/tests/components/nintendo_parental_controls/snapshots/test_time.ambr index cc642718d9b..8f55558272f 100644 --- a/tests/components/nintendo_parental_controls/snapshots/test_time.ambr +++ b/tests/components/nintendo_parental_controls/snapshots/test_time.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bedtime alarm', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nobo_hub/conftest.py b/tests/components/nobo_hub/conftest.py new file mode 100644 index 00000000000..06c3351d2de --- /dev/null +++ b/tests/components/nobo_hub/conftest.py @@ -0,0 +1,24 @@ +"""Common fixtures for the Nobø Ecohub tests.""" + +from collections.abc import Generator +from unittest.mock import AsyncMock, patch + +import pytest + + +@pytest.fixture +def mock_setup_entry() -> Generator[AsyncMock]: + """Override async_setup_entry.""" + with patch( + "homeassistant.components.nobo_hub.async_setup_entry", return_value=True + ) as mock_setup_entry: + yield mock_setup_entry + + +@pytest.fixture +def mock_unload_entry() -> Generator[AsyncMock]: + """Override async_unload_entry.""" + with patch( + "homeassistant.components.nobo_hub.async_unload_entry", return_value=True + ) as mock_unload_entry: + yield mock_unload_entry diff --git a/tests/components/nobo_hub/test_config_flow.py b/tests/components/nobo_hub/test_config_flow.py index 61c84f90cd8..11e74d63bd5 100644 --- a/tests/components/nobo_hub/test_config_flow.py +++ b/tests/components/nobo_hub/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Nobø Ecohub config flow.""" -from unittest.mock import PropertyMock, patch +from unittest.mock import AsyncMock, PropertyMock, patch from homeassistant import config_entries from homeassistant.components.nobo_hub.const import CONF_OVERRIDE_TYPE, DOMAIN @@ -10,7 +10,10 @@ from homeassistant.data_entry_flow import FlowResultType from tests.common import MockConfigEntry -async def test_configure_with_discover(hass: HomeAssistant) -> None: +async def test_configure_with_discover( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, +) -> None: """Test configure with discover.""" with patch( "pynobo.nobo.async_discover_hubs", @@ -40,10 +43,6 @@ async def test_configure_with_discover(hass: HomeAssistant) -> None: create=True, return_value={"name": "My Nobø Ecohub"}, ), - patch( - "homeassistant.components.nobo_hub.async_setup_entry", - return_value=True, - ) as mock_setup_entry, ): result3 = await hass.config_entries.flow.async_configure( result2["flow_id"], @@ -64,7 +63,10 @@ async def test_configure_with_discover(hass: HomeAssistant) -> None: mock_setup_entry.assert_awaited_once() -async def test_configure_manual(hass: HomeAssistant) -> None: +async def test_configure_manual( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, +) -> None: """Test manual configuration when no hubs are discovered.""" with patch( "pynobo.nobo.async_discover_hubs", @@ -85,10 +87,6 @@ async def test_configure_manual(hass: HomeAssistant) -> None: create=True, return_value={"name": "My Nobø Ecohub"}, ), - patch( - "homeassistant.components.nobo_hub.async_setup_entry", - return_value=True, - ) as mock_setup_entry, ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -110,7 +108,10 @@ async def test_configure_manual(hass: HomeAssistant) -> None: mock_setup_entry.assert_awaited_once() -async def test_configure_user_selected_manual(hass: HomeAssistant) -> None: +async def test_configure_user_selected_manual( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, +) -> None: """Test configuration when user selects manual.""" with patch( "pynobo.nobo.async_discover_hubs", @@ -138,10 +139,6 @@ async def test_configure_user_selected_manual(hass: HomeAssistant) -> None: create=True, return_value={"name": "My Nobø Ecohub"}, ), - patch( - "homeassistant.components.nobo_hub.async_setup_entry", - return_value=True, - ) as mock_setup_entry, ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -256,7 +253,11 @@ async def test_configure_cannot_connect(hass: HomeAssistant) -> None: mock_connect.assert_awaited_once_with("1.1.1.1", "123456789012") -async def test_options_flow(hass: HomeAssistant) -> None: +async def test_options_flow( + hass: HomeAssistant, + mock_setup_entry: AsyncMock, + mock_unload_entry: AsyncMock, +) -> None: """Test the options flow.""" config_entry = MockConfigEntry( domain="nobo_hub", @@ -264,12 +265,9 @@ async def test_options_flow(hass: HomeAssistant) -> None: data={"serial": "123456789012", "ip_address": "1.1.1.1", "auto_discover": True}, ) config_entry.add_to_hass(hass) - with patch( - "homeassistant.components.nobo_hub.async_setup_entry", return_value=True - ): - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + mock_setup_entry.reset_mock() result = await hass.config_entries.options.async_init(config_entry.entry_id) assert result["type"] is FlowResultType.FORM @@ -281,9 +279,14 @@ async def test_options_flow(hass: HomeAssistant) -> None: CONF_OVERRIDE_TYPE: "Constant", }, ) + await hass.async_block_till_done() + assert mock_unload_entry.await_count == 1 + assert mock_setup_entry.await_count == 1 assert result["type"] is FlowResultType.CREATE_ENTRY assert config_entry.options == {CONF_OVERRIDE_TYPE: "Constant"} + mock_unload_entry.reset_mock() + mock_setup_entry.reset_mock() result = await hass.config_entries.options.async_init(config_entry.entry_id) result = await hass.config_entries.options.async_configure( @@ -292,6 +295,9 @@ async def test_options_flow(hass: HomeAssistant) -> None: CONF_OVERRIDE_TYPE: "Now", }, ) + await hass.async_block_till_done() + assert mock_unload_entry.await_count == 1 + assert mock_setup_entry.await_count == 1 assert result["type"] is FlowResultType.CREATE_ENTRY assert config_entry.options == {CONF_OVERRIDE_TYPE: "Now"} diff --git a/tests/components/nordpool/snapshots/test_sensor.ambr b/tests/components/nordpool/snapshots/test_sensor.ambr index 67dbdaeed77..dbe2d6686cb 100644 --- a/tests/components/nordpool/snapshots/test_sensor.ambr +++ b/tests/components/nordpool/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Currency', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -125,6 +127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exchange rate', 'options': dict({ }), 'original_device_class': None, @@ -229,6 +233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -283,6 +288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last updated', 'options': dict({ }), 'original_device_class': , @@ -332,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -386,6 +393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -440,6 +448,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -495,6 +504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -550,6 +560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -603,6 +614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 time from', 'options': dict({ }), 'original_device_class': , @@ -652,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 time until', 'options': dict({ }), 'original_device_class': , @@ -703,6 +716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -758,6 +772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -813,6 +828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -866,6 +882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 time from', 'options': dict({ }), 'original_device_class': , @@ -915,6 +932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 time until', 'options': dict({ }), 'original_device_class': , @@ -966,6 +984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1021,6 +1040,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1076,6 +1096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1129,6 +1150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak time from', 'options': dict({ }), 'original_device_class': , @@ -1178,6 +1200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak time until', 'options': dict({ }), 'original_device_class': , @@ -1227,6 +1250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Previous price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1279,6 +1303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Currency', 'options': dict({ }), 'original_device_class': None, @@ -1329,6 +1354,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1384,6 +1410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1439,6 +1466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Exchange rate', 'options': dict({ }), 'original_device_class': None, @@ -1488,6 +1516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1542,6 +1571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last updated', 'options': dict({ }), 'original_device_class': , @@ -1591,6 +1621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1645,6 +1676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1699,6 +1731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1754,6 +1787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1809,6 +1843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1862,6 +1897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 time from', 'options': dict({ }), 'original_device_class': , @@ -1911,6 +1947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 1 time until', 'options': dict({ }), 'original_device_class': , @@ -1962,6 +1999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2017,6 +2055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2072,6 +2111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2125,6 +2165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 time from', 'options': dict({ }), 'original_device_class': , @@ -2174,6 +2215,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-peak 2 time until', 'options': dict({ }), 'original_device_class': , @@ -2225,6 +2267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2280,6 +2323,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak highest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2335,6 +2379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak lowest price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2388,6 +2433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak time from', 'options': dict({ }), 'original_device_class': , @@ -2437,6 +2483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Peak time until', 'options': dict({ }), 'original_device_class': , @@ -2486,6 +2533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Previous price', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/ntfy/snapshots/test_event.ambr b/tests/components/ntfy/snapshots/test_event.ambr index 065114fd851..40c5f4f4122 100644 --- a/tests/components/ntfy/snapshots/test_event.ambr +++ b/tests/components/ntfy/snapshots/test_event.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ntfy/snapshots/test_notify.ambr b/tests/components/ntfy/snapshots/test_notify.ambr index 34320ed5655..73af9a21228 100644 --- a/tests/components/ntfy/snapshots/test_notify.ambr +++ b/tests/components/ntfy/snapshots/test_notify.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ntfy/snapshots/test_sensor.ambr b/tests/components/ntfy/snapshots/test_sensor.ambr index b475b1ee0bc..8812bcf1345 100644 --- a/tests/components/ntfy/snapshots/test_sensor.ambr +++ b/tests/components/ntfy/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Attachment bandwidth limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Attachment expiry duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Attachment file size limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -188,6 +191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Attachment storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -244,6 +248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Attachment storage limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -300,6 +305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Attachment storage remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -356,6 +362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Email usage limit', 'options': dict({ }), 'original_device_class': None, @@ -405,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Emails remaining', 'options': dict({ }), 'original_device_class': None, @@ -454,6 +462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Emails sent', 'options': dict({ }), 'original_device_class': None, @@ -503,6 +512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Messages expiry duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -559,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Messages published', 'options': dict({ }), 'original_device_class': None, @@ -608,6 +619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Messages remaining', 'options': dict({ }), 'original_device_class': None, @@ -657,6 +669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Messages usage limit', 'options': dict({ }), 'original_device_class': None, @@ -706,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phone calls made', 'options': dict({ }), 'original_device_class': None, @@ -755,6 +769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phone calls remaining', 'options': dict({ }), 'original_device_class': None, @@ -804,6 +819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phone calls usage limit', 'options': dict({ }), 'original_device_class': None, @@ -853,6 +869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserved topics', 'options': dict({ }), 'original_device_class': None, @@ -902,6 +919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserved topics limit', 'options': dict({ }), 'original_device_class': None, @@ -951,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reserved topics remaining', 'options': dict({ }), 'original_device_class': None, @@ -1000,6 +1019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscription tier', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nuki/snapshots/test_binary_sensor.ambr b/tests/components/nuki/snapshots/test_binary_sensor.ambr index 88e803115bc..14333ea7035 100644 --- a/tests/components/nuki/snapshots/test_binary_sensor.ambr +++ b/tests/components/nuki/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ring Action', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/nuki/snapshots/test_lock.ambr b/tests/components/nuki/snapshots/test_lock.ambr index 07a0f048fe1..307544443dd 100644 --- a/tests/components/nuki/snapshots/test_lock.ambr +++ b/tests/components/nuki/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/nuki/snapshots/test_sensor.ambr b/tests/components/nuki/snapshots/test_sensor.ambr index f25d18e425a..26c571aa40b 100644 --- a/tests/components/nuki/snapshots/test_sensor.ambr +++ b/tests/components/nuki/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/number/test_device_action.py b/tests/components/number/test_device_action.py index 6b24c15f18a..a0b118ab50e 100644 --- a/tests/components/number/test_device_action.py +++ b/tests/components/number/test_device_action.py @@ -24,11 +24,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/nyt_games/snapshots/test_sensor.ambr b/tests/components/nyt_games/snapshots/test_sensor.ambr index 10fddcfa365..7181cced6a9 100644 --- a/tests/components/nyt_games/snapshots/test_sensor.ambr +++ b/tests/components/nyt_games/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current streak', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest streak', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last played', 'options': dict({ }), 'original_device_class': , @@ -183,6 +186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Played', 'options': dict({ }), 'original_device_class': None, @@ -235,6 +239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Won', 'options': dict({ }), 'original_device_class': None, @@ -287,6 +292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Played', 'options': dict({ }), 'original_device_class': None, @@ -339,6 +345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total pangrams found', 'options': dict({ }), 'original_device_class': None, @@ -391,6 +398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total words found', 'options': dict({ }), 'original_device_class': None, @@ -443,6 +451,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current streak', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -499,6 +508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest streak', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -555,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Played', 'options': dict({ }), 'original_device_class': None, @@ -607,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Won', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/octoprint/snapshots/test_number.ambr b/tests/components/octoprint/snapshots/test_number.ambr index e41f35affb3..ed8903fd5dd 100644 --- a/tests/components/octoprint/snapshots/test_number.ambr +++ b/tests/components/octoprint/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bed temperature', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extruder 1 temperature', 'options': dict({ }), 'original_device_class': , @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extruder temperature', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/ohme/snapshots/test_button.ambr b/tests/components/ohme/snapshots/test_button.ambr index 88cf6327bcf..77932a2a09c 100644 --- a/tests/components/ohme/snapshots/test_button.ambr +++ b/tests/components/ohme/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Approve charge', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ohme/snapshots/test_number.ambr b/tests/components/ohme/snapshots/test_number.ambr index 80ee4d30d9c..38a84ef2f6e 100644 --- a/tests/components/ohme/snapshots/test_number.ambr +++ b/tests/components/ohme/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preconditioning duration', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target percentage', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ohme/snapshots/test_select.ambr b/tests/components/ohme/snapshots/test_select.ambr index 1897e146c01..47c91e2182f 100644 --- a/tests/components/ohme/snapshots/test_select.ambr +++ b/tests/components/ohme/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge mode', 'options': dict({ }), 'original_device_class': None, @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ohme/snapshots/test_sensor.ambr b/tests/components/ohme/snapshots/test_sensor.ambr index 7e7758c58cd..4f4b8e138c9 100644 --- a/tests/components/ohme/snapshots/test_sensor.ambr +++ b/tests/components/ohme/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge slots', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -185,6 +188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -251,6 +255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -310,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -366,6 +372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/ohme/snapshots/test_switch.ambr b/tests/components/ohme/snapshots/test_switch.ambr index ef91187f160..61f4cf875dd 100644 --- a/tests/components/ohme/snapshots/test_switch.ambr +++ b/tests/components/ohme/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock buttons', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Price cap', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Require approval', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep when inactive', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ohme/snapshots/test_time.ambr b/tests/components/ohme/snapshots/test_time.ambr index 1f77bb1f17a..95fe902facf 100644 --- a/tests/components/ohme/snapshots/test_time.ambr +++ b/tests/components/ohme/snapshots/test_time.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target time', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/omnilogic/snapshots/test_sensor.ambr b/tests/components/omnilogic/snapshots/test_sensor.ambr index f5de91b4199..fba8ff051e2 100644 --- a/tests/components/omnilogic/snapshots/test_sensor.ambr +++ b/tests/components/omnilogic/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SCRUBBED Air Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SCRUBBED Spa Water Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/omnilogic/snapshots/test_switch.ambr b/tests/components/omnilogic/snapshots/test_switch.ambr index 34cd555edf8..4c165e6bbd2 100644 --- a/tests/components/omnilogic/snapshots/test_switch.ambr +++ b/tests/components/omnilogic/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SCRUBBED Spa Filter Pump ', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SCRUBBED Spa Spa Jets ', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ondilo_ico/snapshots/test_sensor.ambr b/tests/components/ondilo_ico/snapshots/test_sensor.ambr index 81274bc3a76..9aa850329c8 100644 --- a/tests/components/ondilo_ico/snapshots/test_sensor.ambr +++ b/tests/components/ondilo_ico/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oxydo reduction potential', 'options': dict({ }), 'original_device_class': None, @@ -127,6 +129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH', 'options': dict({ }), 'original_device_class': , @@ -179,6 +182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RSSI', 'options': dict({ }), 'original_device_class': None, @@ -231,6 +235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt', 'options': dict({ }), 'original_device_class': None, @@ -283,6 +288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TDS', 'options': dict({ }), 'original_device_class': None, @@ -335,6 +341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -391,6 +398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -444,6 +452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oxydo reduction potential', 'options': dict({ }), 'original_device_class': None, @@ -496,6 +505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH', 'options': dict({ }), 'original_device_class': , @@ -548,6 +558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RSSI', 'options': dict({ }), 'original_device_class': None, @@ -600,6 +611,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Salt', 'options': dict({ }), 'original_device_class': None, @@ -652,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TDS', 'options': dict({ }), 'original_device_class': None, @@ -704,6 +717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/onedrive/snapshots/test_sensor.ambr b/tests/components/onedrive/snapshots/test_sensor.ambr index 53bcf39eeeb..66b207c63b9 100644 --- a/tests/components/onedrive/snapshots/test_sensor.ambr +++ b/tests/components/onedrive/snapshots/test_sensor.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Drive state', 'options': dict({ }), 'original_device_class': , @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -138,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total available storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -194,6 +197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Used storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/onewire/const.py b/tests/components/onewire/const.py index 2f58766f031..74b7c9c4d57 100644 --- a/tests/components/onewire/const.py +++ b/tests/components/onewire/const.py @@ -260,4 +260,12 @@ MOCK_OWPROXY_DEVICES = { "/EDS0066/pressure": [b" 1012.21"], }, }, + "7E.333333333333": { + ATTR_INJECT_READS: { + "/type": [b"EDS"], + "/device_type": [b"EDS0065"], + "/EDS0065/temperature": [b" 13.9375"], + "/EDS0065/humidity": [b" 41.375"], + }, + }, } diff --git a/tests/components/onewire/snapshots/test_binary_sensor.ambr b/tests/components/onewire/snapshots/test_binary_sensor.ambr index 521e5c50925..9f4e3f5d2af 100644 --- a/tests/components/onewire/snapshots/test_binary_sensor.ambr +++ b/tests/components/onewire/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed A', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed B', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 0', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 1', 'options': dict({ }), 'original_device_class': None, @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 2', 'options': dict({ }), 'original_device_class': None, @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 3', 'options': dict({ }), 'original_device_class': None, @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 4', 'options': dict({ }), 'original_device_class': None, @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 5', 'options': dict({ }), 'original_device_class': None, @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 6', 'options': dict({ }), 'original_device_class': None, @@ -510,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed 7', 'options': dict({ }), 'original_device_class': None, @@ -559,6 +570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed A', 'options': dict({ }), 'original_device_class': None, @@ -608,6 +620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensed B', 'options': dict({ }), 'original_device_class': None, @@ -657,6 +670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub short on branch 0', 'options': dict({ }), 'original_device_class': , @@ -707,6 +721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub short on branch 1', 'options': dict({ }), 'original_device_class': , @@ -757,6 +772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub short on branch 2', 'options': dict({ }), 'original_device_class': , @@ -807,6 +823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub short on branch 3', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/onewire/snapshots/test_init.ambr b/tests/components/onewire/snapshots/test_init.ambr index 19ac8720496..d7e0d711c25 100644 --- a/tests/components/onewire/snapshots/test_init.ambr +++ b/tests/components/onewire/snapshots/test_init.ambr @@ -588,6 +588,37 @@ 'via_device_id': None, }) # --- +# name: test_registry[7E.333333333333-entry] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'onewire', + '7E.333333333333', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Embedded Data Systems', + 'model': None, + 'model_id': 'EDS0065', + 'name': '7E.333333333333', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': '333333333333', + 'sw_version': '3.2', + 'via_device_id': None, + }) +# --- # name: test_registry[A6.111111111111-entry] DeviceRegistryEntrySnapshot({ 'area_id': None, diff --git a/tests/components/onewire/snapshots/test_select.ambr b/tests/components/onewire/snapshots/test_select.ambr index d699f717fea..d533e0f0e3d 100644 --- a/tests/components/onewire/snapshots/test_select.ambr +++ b/tests/components/onewire/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature resolution', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/onewire/snapshots/test_sensor.ambr b/tests/components/onewire/snapshots/test_sensor.ambr index f19a168456d..f75169a093c 100644 --- a/tests/components/onewire/snapshots/test_sensor.ambr +++ b/tests/components/onewire/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -79,6 +80,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -136,6 +138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Counter A', 'options': dict({ }), 'original_device_class': None, @@ -245,6 +249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Counter B', 'options': dict({ }), 'original_device_class': None, @@ -297,6 +302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latest voltage A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -354,6 +360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latest voltage B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -411,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latest voltage C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -468,6 +476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latest voltage D', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -525,6 +534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -639,6 +650,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -696,6 +708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage D', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -753,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -810,6 +824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HIH3600 humidity', 'options': dict({ }), 'original_device_class': , @@ -864,6 +879,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HIH4000 humidity', 'options': dict({ }), 'original_device_class': , @@ -918,6 +934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HIH5030 humidity', 'options': dict({ }), 'original_device_class': , @@ -972,6 +989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HTM1735 humidity', 'options': dict({ }), 'original_device_class': , @@ -1026,6 +1044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1080,6 +1099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1134,6 +1154,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1191,6 +1212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1248,6 +1270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VAD voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1305,6 +1328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VDD voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1362,6 +1386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VIS voltage difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1419,6 +1444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1476,6 +1502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1533,6 +1560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1590,6 +1618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1647,6 +1676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermocouple K temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1704,6 +1734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VIS voltage gradient', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1761,6 +1792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1818,6 +1850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1875,6 +1908,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1932,6 +1966,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1986,6 +2021,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -2040,6 +2076,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2097,6 +2134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2154,6 +2192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2211,6 +2250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2245,6 +2285,119 @@ 'state': '13.9375', }) # --- +# name: test_sensors[sensor.7e_333333333333_humidity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.7e_333333333333_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Humidity', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Humidity', + 'platform': 'onewire', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '/7E.333333333333/EDS0065/humidity', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.7e_333333333333_humidity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'humidity', + 'device_file': '/7E.333333333333/EDS0065/humidity', + 'friendly_name': '7E.333333333333 Humidity', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.7e_333333333333_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '41.375', + }) +# --- +# name: test_sensors[sensor.7e_333333333333_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.7e_333333333333_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'onewire', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '/7E.333333333333/EDS0065/temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.7e_333333333333_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'device_file': '/7E.333333333333/EDS0065/temperature', + 'friendly_name': '7E.333333333333 Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.7e_333333333333_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '13.9375', + }) +# --- # name: test_sensors[sensor.a6_111111111111_hih3600_humidity-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -2268,6 +2421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HIH3600 humidity', 'options': dict({ }), 'original_device_class': , @@ -2322,6 +2476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HIH4000 humidity', 'options': dict({ }), 'original_device_class': , @@ -2376,6 +2531,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HIH5030 humidity', 'options': dict({ }), 'original_device_class': , @@ -2430,6 +2586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HTM1735 humidity', 'options': dict({ }), 'original_device_class': , @@ -2484,6 +2641,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2538,6 +2696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -2592,6 +2751,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2649,6 +2809,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2706,6 +2867,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VAD voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2763,6 +2925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VDD voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2820,6 +2983,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VIS voltage difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2877,6 +3041,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2931,6 +3096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raw humidity', 'options': dict({ }), 'original_device_class': , @@ -2985,6 +3151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3042,6 +3209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3099,6 +3267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3156,6 +3325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wetness 0', 'options': dict({ }), 'original_device_class': , @@ -3210,6 +3380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wetness 1', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/onewire/snapshots/test_switch.ambr b/tests/components/onewire/snapshots/test_switch.ambr index 025fbe1b64b..ec6ed376b47 100644 --- a/tests/components/onewire/snapshots/test_switch.ambr +++ b/tests/components/onewire/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch A', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch B', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output A', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output B', 'options': dict({ }), 'original_device_class': None, @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current A/D control', 'options': dict({ }), 'original_device_class': None, @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 0', 'options': dict({ }), 'original_device_class': None, @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 1', 'options': dict({ }), 'original_device_class': None, @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 2', 'options': dict({ }), 'original_device_class': None, @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 3', 'options': dict({ }), 'original_device_class': None, @@ -510,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 4', 'options': dict({ }), 'original_device_class': None, @@ -559,6 +570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 5', 'options': dict({ }), 'original_device_class': None, @@ -608,6 +620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 6', 'options': dict({ }), 'original_device_class': None, @@ -657,6 +670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Latch 7', 'options': dict({ }), 'original_device_class': None, @@ -706,6 +720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 0', 'options': dict({ }), 'original_device_class': None, @@ -755,6 +770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 1', 'options': dict({ }), 'original_device_class': None, @@ -804,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 2', 'options': dict({ }), 'original_device_class': None, @@ -853,6 +870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 3', 'options': dict({ }), 'original_device_class': None, @@ -902,6 +920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 4', 'options': dict({ }), 'original_device_class': None, @@ -951,6 +970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 5', 'options': dict({ }), 'original_device_class': None, @@ -1000,6 +1020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 6', 'options': dict({ }), 'original_device_class': None, @@ -1049,6 +1070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output 7', 'options': dict({ }), 'original_device_class': None, @@ -1098,6 +1120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output A', 'options': dict({ }), 'original_device_class': None, @@ -1147,6 +1170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Programmed input-output B', 'options': dict({ }), 'original_device_class': None, @@ -1196,6 +1220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current A/D control', 'options': dict({ }), 'original_device_class': None, @@ -1245,6 +1270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leaf sensor 0', 'options': dict({ }), 'original_device_class': None, @@ -1294,6 +1320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leaf sensor 1', 'options': dict({ }), 'original_device_class': None, @@ -1343,6 +1370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leaf sensor 2', 'options': dict({ }), 'original_device_class': None, @@ -1392,6 +1420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Leaf sensor 3', 'options': dict({ }), 'original_device_class': None, @@ -1441,6 +1470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture sensor 0', 'options': dict({ }), 'original_device_class': None, @@ -1490,6 +1520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture sensor 1', 'options': dict({ }), 'original_device_class': None, @@ -1539,6 +1570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture sensor 2', 'options': dict({ }), 'original_device_class': None, @@ -1588,6 +1620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture sensor 3', 'options': dict({ }), 'original_device_class': None, @@ -1637,6 +1670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub branch 0', 'options': dict({ }), 'original_device_class': None, @@ -1686,6 +1720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub branch 1', 'options': dict({ }), 'original_device_class': None, @@ -1735,6 +1770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub branch 2', 'options': dict({ }), 'original_device_class': None, @@ -1784,6 +1820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hub branch 3', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/onkyo/snapshots/test_media_player.ambr b/tests/components/onkyo/snapshots/test_media_player.ambr index 32717a8af43..447e86c4c7c 100644 --- a/tests/components/onkyo/snapshots/test_media_player.ambr +++ b/tests/components/onkyo/snapshots/test_media_player.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX-NR7100', 'options': dict({ }), 'original_device_class': None, @@ -105,6 +106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX-NR7100 Zone 2', 'options': dict({ }), 'original_device_class': None, @@ -169,6 +171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX-NR7100 Zone 3', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/onvif/test_init.py b/tests/components/onvif/test_init.py index c176bdcc112..3a4a5dcb33d 100644 --- a/tests/components/onvif/test_init.py +++ b/tests/components/onvif/test_init.py @@ -2,8 +2,6 @@ from unittest.mock import MagicMock, patch -import pytest - from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -12,7 +10,6 @@ from . import MAC, setup_mock_device from tests.common import MockConfigEntry -@pytest.mark.asyncio async def test_migrate_camera_entities_unique_ids(hass: HomeAssistant) -> None: """Test that camera entities unique ids get migrated properly.""" config_entry = MockConfigEntry(domain="onvif", unique_id=MAC) diff --git a/tests/components/open_router/snapshots/test_ai_task.ambr b/tests/components/open_router/snapshots/test_ai_task.ambr index 9d20deac600..de970ecba33 100644 --- a/tests/components/open_router/snapshots/test_ai_task.ambr +++ b/tests/components/open_router/snapshots/test_ai_task.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'conversation': dict({ 'should_expose': False, diff --git a/tests/components/open_router/snapshots/test_conversation.ambr b/tests/components/open_router/snapshots/test_conversation.ambr index 7182559467c..4189fa3781c 100644 --- a/tests/components/open_router/snapshots/test_conversation.ambr +++ b/tests/components/open_router/snapshots/test_conversation.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'conversation': dict({ 'should_expose': False, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'conversation': dict({ 'should_expose': False, diff --git a/tests/components/openai_conversation/test_config_flow.py b/tests/components/openai_conversation/test_config_flow.py index 202514a77b5..14a6ce49b2e 100644 --- a/tests/components/openai_conversation/test_config_flow.py +++ b/tests/components/openai_conversation/test_config_flow.py @@ -58,7 +58,7 @@ async def test_form(hass: HomeAssistant) -> None: DOMAIN, context={"source": config_entries.SOURCE_USER} ) assert result["type"] is FlowResultType.FORM - assert result["errors"] is None + assert result["errors"] == {} with ( patch( @@ -1049,3 +1049,40 @@ async def test_creating_ai_task_subentry_advanced( CONF_TOP_P: 0.9, CONF_CODE_INTERPRETER: False, } + + +async def test_reauth(hass: HomeAssistant) -> None: + """Test we can reauthenticate.""" + # Pretend we already set up a config entry. + hass.config.components.add("openai_conversation") + mock_config_entry = MockConfigEntry( + domain=DOMAIN, + state=config_entries.ConfigEntryState.LOADED, + ) + + mock_config_entry.add_to_hass(hass) + result = await mock_config_entry.start_reauth_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reauth_confirm" + + with ( + patch( + "homeassistant.components.openai_conversation.config_flow.openai.resources.models.AsyncModels.list", + ), + patch( + "homeassistant.components.openai_conversation.async_setup_entry", + return_value=True, + ), + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_API_KEY: "new_api_key", + }, + ) + await hass.async_block_till_done() + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reauth_successful" + assert mock_config_entry.data[CONF_API_KEY] == "new_api_key" diff --git a/tests/components/openai_conversation/test_init.py b/tests/components/openai_conversation/test_init.py index 70d873752ae..958b662871c 100644 --- a/tests/components/openai_conversation/test_init.py +++ b/tests/components/openai_conversation/test_init.py @@ -25,7 +25,12 @@ from homeassistant.components.openai_conversation.const import ( RECOMMENDED_AI_TASK_OPTIONS, RECOMMENDED_CONVERSATION_OPTIONS, ) -from homeassistant.config_entries import ConfigEntryDisabler, ConfigSubentryData +from homeassistant.config_entries import ( + SOURCE_REAUTH, + ConfigEntryDisabler, + ConfigEntryState, + ConfigSubentryData, +) from homeassistant.const import CONF_API_KEY from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceValidationError @@ -249,16 +254,6 @@ async def test_invalid_config_entry( APIConnectionError(request=httpx.Request(method="GET", url="test")), "Connection error", ), - ( - AuthenticationError( - response=httpx.Response( - status_code=500, request=httpx.Request(method="GET", url="test") - ), - body=None, - message="", - ), - "Invalid API key", - ), ( BadRequestError( response=httpx.Response( @@ -286,6 +281,27 @@ async def test_init_error( assert await async_setup_component(hass, "openai_conversation", {}) await hass.async_block_till_done() assert error in caplog.text + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_init_auth_error( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, +) -> None: + """Test auth error during init errors.""" + with patch( + "openai.resources.models.AsyncModels.list", + side_effect=AuthenticationError( + response=httpx.Response( + status_code=500, request=httpx.Request(method="GET", url="test") + ), + body=None, + message="", + ), + ): + assert await async_setup_component(hass, "openai_conversation", {}) + await hass.async_block_till_done() + assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR @pytest.mark.parametrize( @@ -547,6 +563,56 @@ async def test_generate_content_service_error( ) +@pytest.mark.parametrize( + ("service_name", "patch_path"), + [ + ("generate_image", "openai.resources.images.AsyncImages.generate"), + ("generate_content", "openai.resources.responses.AsyncResponses.create"), + ], +) +@pytest.mark.usefixtures("mock_init_component") +async def test_service_auth_error( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + service_name: str, + patch_path: str, +) -> None: + """Test generate content service handles errors.""" + with ( + patch( + patch_path, + side_effect=AuthenticationError( + response=httpx.Response( + status_code=401, request=httpx.Request(method="GET", url="") + ), + body=None, + message="Reason", + ), + ), + pytest.raises(HomeAssistantError, match="Authentication error"), + ): + await hass.services.async_call( + "openai_conversation", + service_name, + { + "config_entry": mock_config_entry.entry_id, + "prompt": "Image of an epic fail", + }, + blocking=True, + return_response=True, + ) + await hass.async_block_till_done() + flows = hass.config_entries.flow.async_progress() + assert len(flows) == 1 + + flow = flows[0] + assert flow["step_id"] == "reauth_confirm" + assert flow["handler"] == DOMAIN + assert "context" in flow + assert flow["context"]["source"] == SOURCE_REAUTH + assert flow["context"]["entry_id"] == mock_config_entry.entry_id + + async def test_migration_from_v1( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/openevse/snapshots/test_sensor.ambr b/tests/components/openevse/snapshots/test_sensor.ambr index 6d4473fdcf4..e432d0e75f5 100644 --- a/tests/components/openevse/snapshots/test_sensor.ambr +++ b/tests/components/openevse/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,10 +79,14 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge time elapsed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), 'original_device_class': , 'original_icon': None, @@ -132,6 +137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': None, @@ -182,6 +188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IR temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -238,6 +245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RTC temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -294,10 +302,14 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), 'original_device_class': , 'original_icon': None, @@ -350,10 +362,14 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Usage this session', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), 'original_device_class': , 'original_icon': None, diff --git a/tests/components/openevse/test_config_flow.py b/tests/components/openevse/test_config_flow.py index 22a4b9afb05..64406f57356 100644 --- a/tests/components/openevse/test_config_flow.py +++ b/tests/components/openevse/test_config_flow.py @@ -3,11 +3,11 @@ from ipaddress import ip_address from unittest.mock import AsyncMock, MagicMock -from openevsehttp.exceptions import MissingSerial +from openevsehttp.exceptions import AuthenticationError, MissingSerial from homeassistant.components.openevse.const import DOMAIN from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, SOURCE_ZEROCONF -from homeassistant.const import CONF_HOST +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo @@ -22,21 +22,17 @@ async def test_user_flow( ) -> None: """Test user flow create entry with bad charger.""" result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, + DOMAIN, context={"source": SOURCE_USER} ) assert result["type"] is FlowResultType.FORM assert result["step_id"] == "user" result = await hass.config_entries.flow.async_configure( - result["flow_id"], - {CONF_HOST: "10.0.0.131"}, + result["flow_id"], {CONF_HOST: "10.0.0.131"} ) assert result["type"] is FlowResultType.CREATE_ENTRY assert result["title"] == "OpenEVSE 10.0.0.131" - assert result["data"] == { - CONF_HOST: "10.0.0.131", - } + assert result["data"] == {CONF_HOST: "10.0.0.131"} assert result["result"].unique_id == "deadbeeffeed" @@ -47,30 +43,25 @@ async def test_user_flow_flaky( ) -> None: """Test user flow create entry with flaky charger.""" result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, + DOMAIN, context={"source": SOURCE_USER} ) assert result["type"] is FlowResultType.FORM assert result["step_id"] == "user" mock_charger.test_and_get.side_effect = TimeoutError result = await hass.config_entries.flow.async_configure( - result["flow_id"], - {CONF_HOST: "10.0.0.131"}, + result["flow_id"], {CONF_HOST: "10.0.0.131"} ) assert result["type"] is FlowResultType.FORM assert result["step_id"] == "user" - assert result["errors"] == {"host": "cannot_connect"} + assert result["errors"] == {"base": "cannot_connect"} mock_charger.test_and_get.side_effect = None result = await hass.config_entries.flow.async_configure( - result["flow_id"], - {CONF_HOST: "10.0.0.131"}, + result["flow_id"], {CONF_HOST: "10.0.0.131"} ) assert result["type"] is FlowResultType.CREATE_ENTRY assert result["title"] == "OpenEVSE 10.0.0.131" - assert result["data"] == { - CONF_HOST: "10.0.0.131", - } + assert result["data"] == {CONF_HOST: "10.0.0.131"} assert result["result"].unique_id == "deadbeeffeed" @@ -83,6 +74,67 @@ async def test_user_flow_duplicate( """Test user flow aborts when config entry already exists.""" mock_config_entry.add_to_hass(hass) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: "192.168.1.100"} + ) + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + +async def test_user_flow_no_serial( + hass: HomeAssistant, + mock_charger: MagicMock, + mock_setup_entry: AsyncMock, +) -> None: + """Test user flow handles missing serial gracefully.""" + mock_charger.test_and_get.side_effect = [{}, MissingSerial] + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: "10.0.0.131"} + ) + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "OpenEVSE 10.0.0.131" + assert result["result"].unique_id is None + + +async def test_import_flow_no_serial( + hass: HomeAssistant, + mock_charger: MagicMock, + mock_setup_entry: AsyncMock, +) -> None: + """Test import flow handles missing serial gracefully.""" + mock_charger.test_and_get.side_effect = [{}, MissingSerial] + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data={CONF_HOST: "10.0.0.131"} + ) + + # Assert the flow continued to create the entry + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "OpenEVSE 10.0.0.131" + assert result["result"].unique_id is None + + +async def test_user_flow_with_auth( + hass: HomeAssistant, + mock_charger: MagicMock, + mock_setup_entry: AsyncMock, +) -> None: + """Test user flow create entry with authentication.""" + mock_charger.test_and_get.side_effect = [ + AuthenticationError, + {"serial": "deadbeeffeed"}, + ] result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, @@ -91,11 +143,89 @@ async def test_user_flow_duplicate( assert result["step_id"] == "user" result = await hass.config_entries.flow.async_configure( - result["flow_id"], - {CONF_HOST: "192.168.1.100"}, + result["flow_id"], {CONF_HOST: "10.0.0.131"} ) - assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "already_configured" + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "auth" + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "OpenEVSE 10.0.0.131" + assert result["data"] == { + CONF_HOST: "10.0.0.131", + CONF_USERNAME: "fakeuser", + CONF_PASSWORD: "muchpassword", + } + assert result["result"].unique_id == "deadbeeffeed" + + +async def test_user_flow_with_auth_error( + hass: HomeAssistant, mock_charger: MagicMock +) -> None: + """Test user flow create entry with authentication error.""" + mock_charger.test_and_get.side_effect = [ + AuthenticationError, + AuthenticationError, + {}, + ] + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_HOST: "10.0.0.131"}, + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "auth" + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"]["base"] == "invalid_auth" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + assert result["type"] is FlowResultType.CREATE_ENTRY + + +async def test_user_flow_with_missing_serial( + hass: HomeAssistant, mock_charger: MagicMock +) -> None: + """Test user flow create entry with authentication error.""" + mock_charger.test_and_get.side_effect = [AuthenticationError, MissingSerial] + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: "10.0.0.131"} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "auth" + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "OpenEVSE 10.0.0.131" + assert result["data"] == { + CONF_HOST: "10.0.0.131", + CONF_USERNAME: "fakeuser", + CONF_PASSWORD: "muchpassword", + } + assert result["result"].unique_id is None async def test_import_flow( @@ -109,9 +239,7 @@ async def test_import_flow( ) assert result["type"] is FlowResultType.CREATE_ENTRY assert result["title"] == "OpenEVSE 10.0.0.131" - assert result["data"] == { - CONF_HOST: "10.0.0.131", - } + assert result["data"] == {CONF_HOST: "10.0.0.131"} assert result["result"].unique_id == "deadbeeffeed" @@ -243,7 +371,94 @@ async def test_zeroconf_connection_error( ) assert result["type"] is FlowResultType.ABORT - assert result["reason"] == "cannot_connect" + assert result["reason"] == "unavailable_host" + + +async def test_zeroconf_auth(hass: HomeAssistant, mock_charger: MagicMock) -> None: + """Test zeroconf discovery with connection failure.""" + mock_charger.test_and_get.side_effect = [AuthenticationError, {}] + discovery_info = ZeroconfServiceInfo( + ip_address=ip_address("192.168.1.123"), + ip_addresses=[ip_address("192.168.1.123"), ip_address("2001:db8::1")], + hostname="openevse-deadbeeffeed.local.", + name="openevse-deadbeeffeed._openevse._tcp.local.", + port=80, + properties={"id": "deadbeeffeed", "type": "openevse"}, + type="_openevse._tcp.local.", + ) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_ZEROCONF}, + data=discovery_info, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "auth" + assert not result["errors"] + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == { + CONF_HOST: "192.168.1.123", + CONF_USERNAME: "fakeuser", + CONF_PASSWORD: "muchpassword", + } + + +async def test_zeroconf_auth_failure( + hass: HomeAssistant, mock_charger: MagicMock +) -> None: + """Test zeroconf discovery with connection failure.""" + mock_charger.test_and_get.side_effect = [ + AuthenticationError, + AuthenticationError, + {}, + ] + discovery_info = ZeroconfServiceInfo( + ip_address=ip_address("192.168.1.123"), + ip_addresses=[ip_address("192.168.1.123"), ip_address("2001:db8::1")], + hostname="openevse-deadbeeffeed.local.", + name="openevse-deadbeeffeed._openevse._tcp.local.", + port=80, + properties={"id": "deadbeeffeed", "type": "openevse"}, + type="_openevse._tcp.local.", + ) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_ZEROCONF}, + data=discovery_info, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "auth" + assert not result["errors"] + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "auth" + assert result["errors"] == {"base": "invalid_auth"} + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_USERNAME: "fakeuser", CONF_PASSWORD: "muchpassword"}, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == { + CONF_HOST: "192.168.1.123", + CONF_USERNAME: "fakeuser", + CONF_PASSWORD: "muchpassword", + } async def test_zeroconf_already_configured_host( @@ -271,43 +486,3 @@ async def test_zeroconf_already_configured_host( # Should abort because the host matches an existing entry assert result["type"] is FlowResultType.ABORT assert result["reason"] == "already_configured" - - -async def test_user_flow_no_serial( - hass: HomeAssistant, - mock_charger: MagicMock, - mock_setup_entry: AsyncMock, -) -> None: - """Test user flow handles missing serial gracefully.""" - mock_charger.test_and_get.side_effect = [{}, MissingSerial] - - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - ) - assert result["type"] is FlowResultType.FORM - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - {CONF_HOST: "10.0.0.131"}, - ) - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == "OpenEVSE 10.0.0.131" - assert result["result"].unique_id is None - - -async def test_import_flow_no_serial( - hass: HomeAssistant, - mock_charger: MagicMock, - mock_setup_entry: AsyncMock, -) -> None: - """Test import flow handles missing serial gracefully.""" - mock_charger.test_and_get.side_effect = [{}, MissingSerial] - - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data={CONF_HOST: "10.0.0.131"} - ) - - # Assert the flow continued to create the entry - assert result["type"] is FlowResultType.CREATE_ENTRY - assert result["title"] == "OpenEVSE 10.0.0.131" - assert result["result"].unique_id is None diff --git a/tests/components/openevse/test_init.py b/tests/components/openevse/test_init.py new file mode 100644 index 00000000000..5d99806abc0 --- /dev/null +++ b/tests/components/openevse/test_init.py @@ -0,0 +1,41 @@ +"""Tests for the OpenEVSE integration.""" + +from unittest.mock import MagicMock + +from homeassistant.config_entries import ConfigEntryState +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry + + +async def test_setup_entry_timeout( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, +) -> None: + """Test setup entry raises ConfigEntryNotReady on timeout.""" + mock_charger.test_and_get.side_effect = TimeoutError + + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_unload_entry( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, +) -> None: + """Test unload entry.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.LOADED + + await hass.config_entries.async_unload(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.NOT_LOADED diff --git a/tests/components/openevse/test_sensor.py b/tests/components/openevse/test_sensor.py index 377314f62d2..67a656bf0d9 100644 --- a/tests/components/openevse/test_sensor.py +++ b/tests/components/openevse/test_sensor.py @@ -5,8 +5,12 @@ from unittest.mock import MagicMock import pytest from syrupy.assertion import SnapshotAssertion +from homeassistant.components.openevse.const import DOMAIN +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.const import CONF_HOST, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er +from homeassistant.helpers import entity_registry as er, issue_registry as ir +from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, snapshot_platform @@ -44,10 +48,96 @@ async def test_disabled_by_default_entities( assert entry.disabled assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION - state = hass.states.get("sensor.openevse_mock_config_temperature") + state = hass.states.get("sensor.openevse_mock_config_rtc_temperature") assert state is None entry = entity_registry.async_get("sensor.openevse_mock_config_rtc_temperature") assert entry assert entry.disabled assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + +async def test_sensor_unavailable_on_coordinator_timeout( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, +) -> None: + """Test sensors become unavailable when coordinator times out.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get("sensor.openevse_mock_config_charging_status") + assert state + assert state.state != STATE_UNAVAILABLE + + mock_charger.update.side_effect = TimeoutError("Connection timed out") + await mock_config_entry.runtime_data.async_refresh() + await hass.async_block_till_done() + + state = hass.states.get("sensor.openevse_mock_config_charging_status") + assert state + assert state.state == STATE_UNAVAILABLE + + +async def test_yaml_import_success( + hass: HomeAssistant, + mock_charger: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test successful YAML import creates deprecated_yaml issue.""" + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + {SENSOR_DOMAIN: {"platform": DOMAIN, CONF_HOST: "192.168.1.100"}}, + ) + await hass.async_block_till_done() + + issue = issue_registry.async_get_issue("homeassistant", "deprecated_yaml") + assert issue is not None + assert issue.issue_domain == DOMAIN + + +async def test_yaml_import_unavailable_host( + hass: HomeAssistant, + mock_charger: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test YAML import with unavailable host creates domain-specific issue.""" + mock_charger.test_and_get.side_effect = TimeoutError("Connection timed out") + + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + {SENSOR_DOMAIN: {"platform": DOMAIN, CONF_HOST: "192.168.1.100"}}, + ) + await hass.async_block_till_done() + + issue = issue_registry.async_get_issue( + DOMAIN, "deprecated_yaml_import_issue_unavailable_host" + ) + assert issue is not None + + +async def test_yaml_import_already_configured( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test YAML import when already configured creates deprecated_yaml issue.""" + # Only add the entry, don't set it up - this allows the YAML platform setup + # to run while the config flow will still see the existing entry + mock_config_entry.add_to_hass(hass) + + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + {SENSOR_DOMAIN: {"platform": DOMAIN, CONF_HOST: "192.168.1.100"}}, + ) + await hass.async_block_till_done() + + # When already configured, it should still create deprecated_yaml issue + issue = issue_registry.async_get_issue("homeassistant", "deprecated_yaml") + assert issue is not None + assert issue.issue_domain == DOMAIN diff --git a/tests/components/openrgb/snapshots/test_light.ambr b/tests/components/openrgb/snapshots/test_light.ambr index bb195cbebaf..167ce82d004 100644 --- a/tests/components/openrgb/snapshots/test_light.ambr +++ b/tests/components/openrgb/snapshots/test_light.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/openrgb/snapshots/test_select.ambr b/tests/components/openrgb/snapshots/test_select.ambr index 3d065969fef..4c0a7f8ff17 100644 --- a/tests/components/openrgb/snapshots/test_select.ambr +++ b/tests/components/openrgb/snapshots/test_select.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Profile', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/openuv/snapshots/test_binary_sensor.ambr b/tests/components/openuv/snapshots/test_binary_sensor.ambr index 704c6b9f8f6..0ecc123dca5 100644 --- a/tests/components/openuv/snapshots/test_binary_sensor.ambr +++ b/tests/components/openuv/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Protection window', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/openuv/snapshots/test_sensor.ambr b/tests/components/openuv/snapshots/test_sensor.ambr index 92c766bcadc..4da4a840a7f 100644 --- a/tests/components/openuv/snapshots/test_sensor.ambr +++ b/tests/components/openuv/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current ozone level', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current UV index', 'options': dict({ }), 'original_device_class': None, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current UV level', 'options': dict({ }), 'original_device_class': , @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max UV index', 'options': dict({ }), 'original_device_class': None, @@ -243,6 +247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin type 1 safe exposure time', 'options': dict({ }), 'original_device_class': None, @@ -295,6 +300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin type 2 safe exposure time', 'options': dict({ }), 'original_device_class': None, @@ -347,6 +353,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin type 3 safe exposure time', 'options': dict({ }), 'original_device_class': None, @@ -399,6 +406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin type 4 safe exposure time', 'options': dict({ }), 'original_device_class': None, @@ -451,6 +459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin type 5 safe exposure time', 'options': dict({ }), 'original_device_class': None, @@ -503,6 +512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin type 6 safe exposure time', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/openweathermap/snapshots/test_sensor.ambr b/tests/components/openweathermap/snapshots/test_sensor.ambr index cc00a7f0e43..8275a316468 100644 --- a/tests/components/openweathermap/snapshots/test_sensor.ambr +++ b/tests/components/openweathermap/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality index', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ }), 'original_device_class': , @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ }), 'original_device_class': , @@ -183,6 +186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen monoxide', 'options': dict({ }), 'original_device_class': , @@ -237,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone', 'options': dict({ }), 'original_device_class': , @@ -291,6 +296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -345,6 +351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -399,6 +406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sulphur dioxide', 'options': dict({ }), 'original_device_class': , @@ -453,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -510,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud coverage', 'options': dict({ }), 'original_device_class': None, @@ -561,6 +571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition', 'options': dict({ }), 'original_device_class': None, @@ -612,6 +623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -669,6 +681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -721,6 +734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation kind', 'options': dict({ }), 'original_device_class': None, @@ -772,6 +786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -829,6 +844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -886,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Snow intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -943,6 +960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1000,6 +1018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -1053,6 +1072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Visibility', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1108,6 +1128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather', 'options': dict({ }), 'original_device_class': None, @@ -1157,6 +1178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather code', 'options': dict({ }), 'original_device_class': None, @@ -1208,6 +1230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -1262,6 +1285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1322,6 +1346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1382,6 +1407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1439,6 +1465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud coverage', 'options': dict({ }), 'original_device_class': None, @@ -1490,6 +1517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condition', 'options': dict({ }), 'original_device_class': None, @@ -1541,6 +1569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1598,6 +1627,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1650,6 +1680,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation kind', 'options': dict({ }), 'original_device_class': None, @@ -1701,6 +1732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1758,6 +1790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1815,6 +1848,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Snow intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1872,6 +1906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1929,6 +1964,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -1982,6 +2018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Visibility', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2037,6 +2074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather', 'options': dict({ }), 'original_device_class': None, @@ -2086,6 +2124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather code', 'options': dict({ }), 'original_device_class': None, @@ -2137,6 +2176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -2191,6 +2231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2251,6 +2292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/openweathermap/snapshots/test_weather.ambr b/tests/components/openweathermap/snapshots/test_weather.ambr index 733545a3f43..28669bcf556 100644 --- a/tests/components/openweathermap/snapshots/test_weather.ambr +++ b/tests/components/openweathermap/snapshots/test_weather.ambr @@ -44,6 +44,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -108,6 +109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -173,6 +175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/osoenergy/snapshots/test_water_heater.ambr b/tests/components/osoenergy/snapshots/test_water_heater.ambr index 208fd3b2aa3..67a48547c63 100644 --- a/tests/components/osoenergy/snapshots/test_water_heater.ambr +++ b/tests/components/osoenergy/snapshots/test_water_heater.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/overseerr/snapshots/test_event.ambr b/tests/components/overseerr/snapshots/test_event.ambr index bfa03d9a2e8..aea1c2158ac 100644 --- a/tests/components/overseerr/snapshots/test_event.ambr +++ b/tests/components/overseerr/snapshots/test_event.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last media event', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/overseerr/snapshots/test_sensor.ambr b/tests/components/overseerr/snapshots/test_sensor.ambr index 2ea19617e8e..f14c763b25d 100644 --- a/tests/components/overseerr/snapshots/test_sensor.ambr +++ b/tests/components/overseerr/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Audio issues', 'options': dict({ }), 'original_device_class': None, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Available requests', 'options': dict({ }), 'original_device_class': None, @@ -125,6 +127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Closed issues', 'options': dict({ }), 'original_device_class': None, @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Declined requests', 'options': dict({ }), 'original_device_class': None, @@ -228,6 +232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Movie requests', 'options': dict({ }), 'original_device_class': None, @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Open issues', 'options': dict({ }), 'original_device_class': None, @@ -331,6 +337,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pending requests', 'options': dict({ }), 'original_device_class': None, @@ -383,6 +390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Processing requests', 'options': dict({ }), 'original_device_class': None, @@ -435,6 +443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subtitle issues', 'options': dict({ }), 'original_device_class': None, @@ -486,6 +495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total issues', 'options': dict({ }), 'original_device_class': None, @@ -537,6 +547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total requests', 'options': dict({ }), 'original_device_class': None, @@ -589,6 +600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TV requests', 'options': dict({ }), 'original_device_class': None, @@ -641,6 +653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Video issues', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/palazzetti/snapshots/test_button.ambr b/tests/components/palazzetti/snapshots/test_button.ambr index bc711cd8cde..5456ee27007 100644 --- a/tests/components/palazzetti/snapshots/test_button.ambr +++ b/tests/components/palazzetti/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Silent', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/palazzetti/snapshots/test_climate.ambr b/tests/components/palazzetti/snapshots/test_climate.ambr index 4ef71fe4e57..ff9eb85c6bf 100644 --- a/tests/components/palazzetti/snapshots/test_climate.ambr +++ b/tests/components/palazzetti/snapshots/test_climate.ambr @@ -37,6 +37,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/palazzetti/snapshots/test_number.ambr b/tests/components/palazzetti/snapshots/test_number.ambr index c700f08a69c..af903c3f9b0 100644 --- a/tests/components/palazzetti/snapshots/test_number.ambr +++ b/tests/components/palazzetti/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Combustion power', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left fan speed', 'options': dict({ }), 'original_device_class': , @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right fan speed', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/palazzetti/snapshots/test_sensor.ambr b/tests/components/palazzetti/snapshots/test_sensor.ambr index 3221430fd23..b1786cb16ca 100644 --- a/tests/components/palazzetti/snapshots/test_sensor.ambr +++ b/tests/components/palazzetti/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air outlet temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hydro temperature 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hydro temperature 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pellet quantity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -406,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -506,6 +513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -562,6 +570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wood combustion temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/paperless_ngx/snapshots/test_sensor.ambr b/tests/components/paperless_ngx/snapshots/test_sensor.ambr index ed023f75726..6319cbc7873 100644 --- a/tests/components/paperless_ngx/snapshots/test_sensor.ambr +++ b/tests/components/paperless_ngx/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Available storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Correspondents', 'options': dict({ }), 'original_device_class': None, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Document types', 'options': dict({ }), 'original_device_class': None, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Documents in inbox', 'options': dict({ }), 'original_device_class': None, @@ -238,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status Celery', 'options': dict({ }), 'original_device_class': , @@ -298,6 +303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status classifier', 'options': dict({ }), 'original_device_class': , @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status database', 'options': dict({ }), 'original_device_class': , @@ -418,6 +425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status index', 'options': dict({ }), 'original_device_class': , @@ -478,6 +486,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status Redis', 'options': dict({ }), 'original_device_class': , @@ -538,6 +547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status sanity', 'options': dict({ }), 'original_device_class': , @@ -594,6 +604,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tags', 'options': dict({ }), 'original_device_class': None, @@ -646,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total characters', 'options': dict({ }), 'original_device_class': None, @@ -698,6 +710,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total documents', 'options': dict({ }), 'original_device_class': None, @@ -750,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total storage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/paperless_ngx/snapshots/test_update.ambr b/tests/components/paperless_ngx/snapshots/test_update.ambr index ee563557613..4df9074f38e 100644 --- a/tests/components/paperless_ngx/snapshots/test_update.ambr +++ b/tests/components/paperless_ngx/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Software', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/peblar/snapshots/test_binary_sensor.ambr b/tests/components/peblar/snapshots/test_binary_sensor.ambr index ed39bbf171b..ecabfe81853 100644 --- a/tests/components/peblar/snapshots/test_binary_sensor.ambr +++ b/tests/components/peblar/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active errors', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active warnings', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/peblar/snapshots/test_button.ambr b/tests/components/peblar/snapshots/test_button.ambr index b46dc0b0eca..2d8a9220d82 100644 --- a/tests/components/peblar/snapshots/test_button.ambr +++ b/tests/components/peblar/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/peblar/snapshots/test_number.ambr b/tests/components/peblar/snapshots/test_number.ambr index f7fd499d112..dec459aa686 100644 --- a/tests/components/peblar/snapshots/test_number.ambr +++ b/tests/components/peblar/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge limit', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/peblar/snapshots/test_select.ambr b/tests/components/peblar/snapshots/test_select.ambr index 95146997039..e0c7d709d87 100644 --- a/tests/components/peblar/snapshots/test_select.ambr +++ b/tests/components/peblar/snapshots/test_select.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart charging', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/peblar/snapshots/test_sensor.ambr b/tests/components/peblar/snapshots/test_sensor.ambr index 2963693d77d..b62a3f8369e 100644 --- a/tests/components/peblar/snapshots/test_sensor.ambr +++ b/tests/components/peblar/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -335,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Limit source', 'options': dict({ }), 'original_device_class': , @@ -405,6 +411,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -461,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -517,6 +525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -573,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -629,6 +639,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Session energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -696,6 +707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -754,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -805,6 +818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -861,6 +875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -917,6 +932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/peblar/snapshots/test_switch.ambr b/tests/components/peblar/snapshots/test_switch.ambr index f3b9775e339..4698bbf8c9a 100644 --- a/tests/components/peblar/snapshots/test_switch.ambr +++ b/tests/components/peblar/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Force single phase', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/peblar/snapshots/test_update.ambr b/tests/components/peblar/snapshots/test_update.ambr index 48a92dcad49..0e69410385b 100644 --- a/tests/components/peblar/snapshots/test_update.ambr +++ b/tests/components/peblar/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Customization', 'options': dict({ }), 'original_device_class': None, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/person/test_trigger.py b/tests/components/person/test_trigger.py index 043c23fd644..a754faae1a7 100644 --- a/tests/components/person/test_trigger.py +++ b/tests/components/person/test_trigger.py @@ -1,8 +1,6 @@ """Test person trigger.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -16,7 +14,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -27,21 +25,6 @@ from tests.components import ( STATE_WORK_ZONE = "work" -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_persons(hass: HomeAssistant) -> list[str]: """Create multiple persons entities associated with different targets.""" @@ -65,7 +48,7 @@ async def test_person_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -94,7 +77,7 @@ async def test_person_home_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the person home triggers when any person changes to a specific state.""" other_entity_ids = set(target_persons) - {entity_id} @@ -123,7 +106,7 @@ async def test_person_home_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -152,7 +135,7 @@ async def test_person_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the person home triggers when the first person changes to a specific state.""" other_entity_ids = set(target_persons) - {entity_id} @@ -180,7 +163,7 @@ async def test_person_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -209,7 +192,7 @@ async def test_person_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the person home triggers when the last person changes to a specific state.""" other_entity_ids = set(target_persons) - {entity_id} diff --git a/tests/components/philips_js/test_device_trigger.py b/tests/components/philips_js/test_device_trigger.py index 8f2e5543f1e..679c482d4b1 100644 --- a/tests/components/philips_js/test_device_trigger.py +++ b/tests/components/philips_js/test_device_trigger.py @@ -1,6 +1,5 @@ """The tests for Philips TV device triggers.""" -import pytest from pytest_unordered import unordered from homeassistant.components import automation @@ -12,11 +11,6 @@ from homeassistant.setup import async_setup_component from tests.common import async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers(hass: HomeAssistant, mock_device) -> None: """Test we get the expected triggers.""" expected_triggers = [ diff --git a/tests/components/ping/snapshots/test_binary_sensor.ambr b/tests/components/ping/snapshots/test_binary_sensor.ambr index c5a97fa5d22..9b7777615e2 100644 --- a/tests/components/ping/snapshots/test_binary_sensor.ambr +++ b/tests/components/ping/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/ping/snapshots/test_sensor.ambr b/tests/components/ping/snapshots/test_sensor.ambr index 7965fb69210..bd8aa1bba99 100644 --- a/tests/components/ping/snapshots/test_sensor.ambr +++ b/tests/components/ping/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Jitter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Packet loss', 'options': dict({ }), 'original_device_class': None, @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Round-trip time average', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -183,6 +186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Round-trip time maximum', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -244,6 +248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Round-trip time minimum', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/plaato/snapshots/test_binary_sensor.ambr b/tests/components/plaato/snapshots/test_binary_sensor.ambr index 2eb77505c11..9c6c855fe7f 100644 --- a/tests/components/plaato/snapshots/test_binary_sensor.ambr +++ b/tests/components/plaato/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Keg Device_Name Leaking', 'options': dict({ }), 'original_device_class': , @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Keg Device_Name Pouring', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/plaato/snapshots/test_sensor.ambr b/tests/components/plaato/snapshots/test_sensor.ambr index a64fe5f1b71..7aa204bf8f1 100644 --- a/tests/components/plaato/snapshots/test_sensor.ambr +++ b/tests/components/plaato/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Alcohol By Volume', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Batch Volume', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Bubbles', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Bubbles Per Minute', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Co2 Volume', 'options': dict({ }), 'original_device_class': None, @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Original Gravity', 'options': dict({ }), 'original_device_class': None, @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Specific Gravity', 'options': dict({ }), 'original_device_class': None, @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Airlock Device_Name Temperature', 'options': dict({ }), 'original_device_class': None, @@ -409,6 +417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Keg Device_Name Beer Left', 'options': dict({ }), 'original_device_class': None, @@ -460,6 +469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Keg Device_Name Last Pour Amount', 'options': dict({ }), 'original_device_class': None, @@ -512,6 +522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Keg Device_Name Percent Beer Left', 'options': dict({ }), 'original_device_class': None, @@ -564,6 +575,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plaato Plaatodevicetype.Keg Device_Name Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/playstation_network/snapshots/test_binary_sensor.ambr b/tests/components/playstation_network/snapshots/test_binary_sensor.ambr index f380f91e9b9..287946396c4 100644 --- a/tests/components/playstation_network/snapshots/test_binary_sensor.ambr +++ b/tests/components/playstation_network/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscribed to PlayStation Plus', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/playstation_network/snapshots/test_media_player.ambr b/tests/components/playstation_network/snapshots/test_media_player.ambr index 891509b351c..2690f100fe1 100644 --- a/tests/components/playstation_network/snapshots/test_media_player.ambr +++ b/tests/components/playstation_network/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -181,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -234,6 +238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -285,6 +290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -341,6 +347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -394,6 +401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -445,6 +453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/playstation_network/snapshots/test_notify.ambr b/tests/components/playstation_network/snapshots/test_notify.ambr index 416b1da46ca..5521ff8793b 100644 --- a/tests/components/playstation_network/snapshots/test_notify.ambr +++ b/tests/components/playstation_network/snapshots/test_notify.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direct message: PublicUniversalFriend', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Group: PublicUniversalFriend', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/playstation_network/snapshots/test_sensor.ambr b/tests/components/playstation_network/snapshots/test_sensor.ambr index 9d582f2953a..55f92c1479c 100644 --- a/tests/components/playstation_network/snapshots/test_sensor.ambr +++ b/tests/components/playstation_network/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bronze trophies', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gold trophies', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last online', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next level', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Online ID', 'options': dict({ }), 'original_device_class': None, @@ -319,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Online status', 'options': dict({ }), 'original_device_class': , @@ -374,6 +381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Platinum trophies', 'options': dict({ }), 'original_device_class': None, @@ -423,6 +431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Silver trophies', 'options': dict({ }), 'original_device_class': None, @@ -472,6 +481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trophy level', 'options': dict({ }), 'original_device_class': None, @@ -520,6 +530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bronze trophies', 'options': dict({ }), 'original_device_class': None, @@ -569,6 +580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gold trophies', 'options': dict({ }), 'original_device_class': None, @@ -618,6 +630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last online', 'options': dict({ }), 'original_device_class': , @@ -667,6 +680,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next level', 'options': dict({ }), 'original_device_class': None, @@ -716,6 +730,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -764,6 +779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Online ID', 'options': dict({ }), 'original_device_class': None, @@ -820,6 +836,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Online status', 'options': dict({ }), 'original_device_class': , @@ -875,6 +892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Platinum trophies', 'options': dict({ }), 'original_device_class': None, @@ -924,6 +942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Silver trophies', 'options': dict({ }), 'original_device_class': None, @@ -973,6 +992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trophy level', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/plugwise/snapshots/test_binary_sensor.ambr b/tests/components/plugwise/snapshots/test_binary_sensor.ambr index d371bb38803..807f98363e5 100644 --- a/tests/components/plugwise/snapshots/test_binary_sensor.ambr +++ b/tests/components/plugwise/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plugwise notification', 'options': dict({ }), 'original_device_class': None, @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -175,6 +178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ }), 'original_device_class': None, @@ -223,6 +227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -272,6 +277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -321,6 +327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -419,6 +427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -468,6 +477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -517,6 +527,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor state', 'options': dict({ }), 'original_device_class': None, @@ -565,6 +576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooling', 'options': dict({ }), 'original_device_class': None, @@ -613,6 +625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooling enabled', 'options': dict({ }), 'original_device_class': None, @@ -661,6 +674,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW state', 'options': dict({ }), 'original_device_class': None, @@ -709,6 +723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flame state', 'options': dict({ }), 'original_device_class': None, @@ -757,6 +772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ }), 'original_device_class': None, @@ -805,6 +821,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Secondary boiler state', 'options': dict({ }), 'original_device_class': None, @@ -853,6 +870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plugwise notification', 'options': dict({ }), 'original_device_class': None, @@ -909,6 +927,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plugwise notification', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/plugwise/snapshots/test_button.ambr b/tests/components/plugwise/snapshots/test_button.ambr index 900d85db527..3f06d95a4dd 100644 --- a/tests/components/plugwise/snapshots/test_button.ambr +++ b/tests/components/plugwise/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reboot', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/plugwise/snapshots/test_climate.ambr b/tests/components/plugwise/snapshots/test_climate.ambr index a71827d24fb..6c608149b8a 100644 --- a/tests/components/plugwise/snapshots/test_climate.ambr +++ b/tests/components/plugwise/snapshots/test_climate.ambr @@ -36,6 +36,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -120,6 +121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -203,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -285,6 +288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -366,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -447,6 +452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -529,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -611,6 +618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -694,6 +702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -777,6 +786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/plugwise/snapshots/test_number.ambr b/tests/components/plugwise/snapshots/test_number.ambr index 922cbb1e2bf..ea54e561595 100644 --- a/tests/components/plugwise/snapshots/test_number.ambr +++ b/tests/components/plugwise/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -261,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -379,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -438,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -497,6 +505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -556,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -615,6 +625,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Domestic hot water setpoint', 'options': dict({ }), 'original_device_class': , @@ -674,6 +685,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum boiler temperature setpoint', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/plugwise/snapshots/test_select.ambr b/tests/components/plugwise/snapshots/test_select.ambr index 90ace520e2d..afe46a818a7 100644 --- a/tests/components/plugwise/snapshots/test_select.ambr +++ b/tests/components/plugwise/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gateway mode', 'options': dict({ }), 'original_device_class': None, @@ -87,6 +88,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Regulation mode', 'options': dict({ }), 'original_device_class': None, @@ -150,6 +152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat schedule', 'options': dict({ }), 'original_device_class': None, @@ -211,6 +214,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone profile', 'options': dict({ }), 'original_device_class': None, @@ -272,6 +276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat schedule', 'options': dict({ }), 'original_device_class': None, @@ -333,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone profile', 'options': dict({ }), 'original_device_class': None, @@ -395,6 +401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat schedule', 'options': dict({ }), 'original_device_class': None, @@ -460,6 +467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat schedule', 'options': dict({ }), 'original_device_class': None, @@ -525,6 +533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat schedule', 'options': dict({ }), 'original_device_class': None, @@ -590,6 +599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermostat schedule', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/plugwise/snapshots/test_sensor.ambr b/tests/components/plugwise/snapshots/test_sensor.ambr index 113fba03b15..23c0c242e39 100644 --- a/tests/components/plugwise/snapshots/test_sensor.ambr +++ b/tests/components/plugwise/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -411,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -464,6 +472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -520,6 +529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -576,6 +586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -629,6 +640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -682,6 +694,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -738,6 +751,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -794,6 +808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -847,6 +862,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -903,6 +919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -959,6 +976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1015,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1071,6 +1090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1127,6 +1147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intended boiler temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1183,6 +1204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1239,6 +1261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1295,6 +1318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1351,6 +1375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1404,6 +1429,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1460,6 +1486,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1516,6 +1543,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1572,6 +1600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': None, @@ -1624,6 +1653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1680,6 +1710,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1736,6 +1767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1792,6 +1824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1845,6 +1878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1901,6 +1935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1957,6 +1992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intended boiler temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2013,6 +2049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Modulation level', 'options': dict({ }), 'original_device_class': None, @@ -2065,6 +2102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2121,6 +2159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2177,6 +2216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2233,6 +2273,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2289,6 +2330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2345,6 +2387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2401,6 +2444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2457,6 +2501,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2513,6 +2558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase one consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2569,6 +2615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase one produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2625,6 +2672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2681,6 +2729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2737,6 +2786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2793,6 +2843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2849,6 +2900,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2905,6 +2957,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2961,6 +3014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumed cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3017,6 +3071,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumed interval', 'options': dict({ }), 'original_device_class': None, @@ -3069,6 +3124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net electricity cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3125,6 +3181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net electricity point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3181,6 +3238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase one', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3237,6 +3295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3293,6 +3352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooling setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3349,6 +3409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3405,6 +3466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -3458,6 +3520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3514,6 +3577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3570,6 +3634,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intended boiler temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3626,6 +3691,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Modulation level', 'options': dict({ }), 'original_device_class': None, @@ -3678,6 +3744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3734,6 +3801,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3790,6 +3858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3846,6 +3915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3902,6 +3972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3958,6 +4029,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4014,6 +4086,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4070,6 +4143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4126,6 +4200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4182,6 +4257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4238,6 +4314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4294,6 +4371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase one consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4350,6 +4428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase one produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4406,6 +4485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase three consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4462,6 +4542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase three produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4518,6 +4599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase two consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4574,6 +4656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase two produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4630,6 +4713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4686,6 +4770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4742,6 +4827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4798,6 +4884,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4854,6 +4941,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4910,6 +4998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4966,6 +5055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumed cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5022,6 +5112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumed interval', 'options': dict({ }), 'original_device_class': None, @@ -5074,6 +5165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net electricity cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5130,6 +5222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net electricity point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5186,6 +5279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase one', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5242,6 +5336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase three', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5298,6 +5393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase two', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5354,6 +5450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5410,6 +5507,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5466,6 +5564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed off-peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5522,6 +5621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5578,6 +5678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5634,6 +5735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5690,6 +5792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase one consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5746,6 +5849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity phase one produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5802,6 +5906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5858,6 +5963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5914,6 +6020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced off-peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5970,6 +6077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6026,6 +6134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6082,6 +6191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced peak point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6138,6 +6248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net electricity cumulative', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6194,6 +6305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Net electricity point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6250,6 +6362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6306,6 +6419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6362,6 +6476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6418,6 +6533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6474,6 +6590,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6530,6 +6647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6586,6 +6704,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6642,6 +6761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6698,6 +6818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6754,6 +6875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6810,6 +6932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6866,6 +6989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6922,6 +7046,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6978,6 +7103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumed interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7034,6 +7160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity produced', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/plugwise/snapshots/test_switch.ambr b/tests/components/plugwise/snapshots/test_switch.ambr index e296b874210..cd961c680cc 100644 --- a/tests/components/plugwise/snapshots/test_switch.ambr +++ b/tests/components/plugwise/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -214,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -311,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -360,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -408,6 +416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -457,6 +466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -506,6 +516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -554,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -603,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -651,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -700,6 +714,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -748,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -797,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -845,6 +862,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -894,6 +912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -942,6 +961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -991,6 +1011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -1040,6 +1061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -1089,6 +1111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -1137,6 +1160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , @@ -1186,6 +1210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -1234,6 +1259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Relay', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/pooldose/snapshots/test_binary_sensor.ambr b/tests/components/pooldose/snapshots/test_binary_sensor.ambr index c02ac675f8c..629ab67b817 100644 --- a/tests/components/pooldose/snapshots/test_binary_sensor.ambr +++ b/tests/components/pooldose/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm relay status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auxiliary relay 1 status', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auxiliary relay 2 status', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auxiliary relay 3 status', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine tank level', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow rate', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP overfeed', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP tank level', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH overfeed', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH tank level', 'options': dict({ }), 'original_device_class': , @@ -510,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Recirculation', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/pooldose/snapshots/test_number.ambr b/tests/components/pooldose/snapshots/test_number.ambr index 83da9ef9f7d..99888bdd727 100644 --- a/tests/components/pooldose/snapshots/test_number.ambr +++ b/tests/components/pooldose/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine overfeed alarm lower limit', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine overfeed alarm upper limit', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine target', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP overfeed alarm lower limit', 'options': dict({ }), 'original_device_class': , @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP overfeed alarm upper limit', 'options': dict({ }), 'original_device_class': , @@ -317,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP target', 'options': dict({ }), 'original_device_class': , @@ -376,6 +382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH overfeed alarm lower limit', 'options': dict({ }), 'original_device_class': , @@ -434,6 +441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH overfeed alarm upper limit', 'options': dict({ }), 'original_device_class': , @@ -492,6 +500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH target', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/pooldose/snapshots/test_select.ambr b/tests/components/pooldose/snapshots/test_select.ambr index a33603463e8..66e8196b83e 100644 --- a/tests/components/pooldose/snapshots/test_select.ambr +++ b/tests/components/pooldose/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine dosing method', 'options': dict({ }), 'original_device_class': None, @@ -86,6 +87,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine dosing set', 'options': dict({ }), 'original_device_class': None, @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow rate unit', 'options': dict({ }), 'original_device_class': None, @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP dosing method', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP dosing set', 'options': dict({ }), 'original_device_class': None, @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH dosing method', 'options': dict({ }), 'original_device_class': None, @@ -379,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH dosing set', 'options': dict({ }), 'original_device_class': None, @@ -436,6 +443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water meter unit', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/pooldose/snapshots/test_sensor.ambr b/tests/components/pooldose/snapshots/test_sensor.ambr index f07064abcc0..fcdc064d544 100644 --- a/tests/components/pooldose/snapshots/test_sensor.ambr +++ b/tests/components/pooldose/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine dosing type', 'options': dict({ }), 'original_device_class': , @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine peristaltic dosing', 'options': dict({ }), 'original_device_class': , @@ -189,6 +192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -242,6 +246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -295,6 +300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP calibration offset', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -348,6 +354,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP calibration slope', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -407,6 +414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP calibration type', 'options': dict({ }), 'original_device_class': , @@ -466,6 +474,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP dosing type', 'options': dict({ }), 'original_device_class': , @@ -519,6 +528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP overfeed alert time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -579,6 +589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ORP peristaltic dosing', 'options': dict({ }), 'original_device_class': , @@ -634,6 +645,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH', 'options': dict({ }), 'original_device_class': , @@ -683,6 +695,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH calibration offset', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -736,6 +749,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH calibration slope', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -796,6 +810,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH calibration type', 'options': dict({ }), 'original_device_class': , @@ -856,6 +871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH dosing type', 'options': dict({ }), 'original_device_class': , @@ -909,6 +925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH overfeed alert time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -968,6 +985,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH peristaltic dosing', 'options': dict({ }), 'original_device_class': , @@ -1022,6 +1040,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1077,6 +1096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Totalizer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/pooldose/snapshots/test_switch.ambr b/tests/components/pooldose/snapshots/test_switch.ambr index ec36a5308ef..784109df739 100644 --- a/tests/components/pooldose/snapshots/test_switch.ambr +++ b/tests/components/pooldose/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency input', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause dosing', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pump monitoring', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/poolsense/snapshots/test_binary_sensor.ambr b/tests/components/poolsense/snapshots/test_binary_sensor.ambr index f0e008d4f70..f26731968ff 100644 --- a/tests/components/poolsense/snapshots/test_binary_sensor.ambr +++ b/tests/components/poolsense/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine status', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/poolsense/snapshots/test_sensor.ambr b/tests/components/poolsense/snapshots/test_sensor.ambr index 07ea998d902..e1e3ab1bd61 100644 --- a/tests/components/poolsense/snapshots/test_sensor.ambr +++ b/tests/components/poolsense/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine', 'options': dict({ }), 'original_device_class': None, @@ -121,6 +123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine high', 'options': dict({ }), 'original_device_class': None, @@ -171,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Chlorine low', 'options': dict({ }), 'original_device_class': None, @@ -221,6 +225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last seen', 'options': dict({ }), 'original_device_class': , @@ -271,6 +276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH', 'options': dict({ }), 'original_device_class': , @@ -321,6 +327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH high', 'options': dict({ }), 'original_device_class': None, @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'pH low', 'options': dict({ }), 'original_device_class': None, @@ -419,6 +427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/portainer/snapshots/test_binary_sensor.ambr b/tests/components/portainer/snapshots/test_binary_sensor.ambr index 7ec3900e49b..918201ac0d7 100644 --- a/tests/components/portainer/snapshots/test_binary_sensor.ambr +++ b/tests/components/portainer/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/portainer/snapshots/test_button.ambr b/tests/components/portainer/snapshots/test_button.ambr index 93305534672..1d05a4d4f95 100644 --- a/tests/components/portainer/snapshots/test_button.ambr +++ b/tests/components/portainer/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart container', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart container', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Prune unused images', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart container', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart container', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart container', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/portainer/snapshots/test_sensor.ambr b/tests/components/portainer/snapshots/test_sensor.ambr index ac57edf5522..4ab22921530 100644 --- a/tests/components/portainer/snapshots/test_sensor.ambr +++ b/tests/components/portainer/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Image', 'options': dict({ }), 'original_device_class': None, @@ -125,6 +127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -243,6 +247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage percentage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -305,6 +310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -364,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -417,6 +424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Image', 'options': dict({ }), 'original_device_class': None, @@ -467,6 +475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -585,6 +595,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage percentage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -647,6 +658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -704,6 +716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'API version', 'options': dict({ }), 'original_device_class': None, @@ -752,6 +765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Architecture', 'options': dict({ }), 'original_device_class': None, @@ -802,6 +816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Container count', 'options': dict({ }), 'original_device_class': None, @@ -853,6 +868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Containers paused', 'options': dict({ }), 'original_device_class': None, @@ -904,6 +920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Containers running', 'options': dict({ }), 'original_device_class': None, @@ -955,6 +972,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Containers stopped', 'options': dict({ }), 'original_device_class': None, @@ -1004,6 +1022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Docker version', 'options': dict({ }), 'original_device_class': None, @@ -1054,6 +1073,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Image count', 'options': dict({ }), 'original_device_class': None, @@ -1103,6 +1123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kernel version', 'options': dict({ }), 'original_device_class': None, @@ -1151,6 +1172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating system', 'options': dict({ }), 'original_device_class': None, @@ -1199,6 +1221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating system version', 'options': dict({ }), 'original_device_class': None, @@ -1249,6 +1272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total CPU', 'options': dict({ }), 'original_device_class': None, @@ -1300,6 +1324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1359,6 +1384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1412,6 +1438,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Image', 'options': dict({ }), 'original_device_class': None, @@ -1462,6 +1489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1521,6 +1549,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1580,6 +1609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage percentage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1642,6 +1672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -1701,6 +1732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1754,6 +1786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Image', 'options': dict({ }), 'original_device_class': None, @@ -1804,6 +1837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1863,6 +1897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1922,6 +1957,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage percentage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1984,6 +2020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -2043,6 +2080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2096,6 +2134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Image', 'options': dict({ }), 'original_device_class': None, @@ -2146,6 +2185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2205,6 +2245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2264,6 +2305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage percentage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2326,6 +2368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/portainer/snapshots/test_switch.ambr b/tests/components/portainer/snapshots/test_switch.ambr index 6e749d8212f..635547f0997 100644 --- a/tests/components/portainer/snapshots/test_switch.ambr +++ b/tests/components/portainer/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Container', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Container', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Container', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Container', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Container', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/powerfox/snapshots/test_sensor.ambr b/tests/components/powerfox/snapshots/test_sensor.ambr index c7ebf625227..9dcdeaf164c 100644 --- a/tests/components/powerfox/snapshots/test_sensor.ambr +++ b/tests/components/powerfox/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avg gas hourly consumption - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avg gas hourly energy - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumption energy - this hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -181,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumption energy - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -235,6 +239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumption - this hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -290,6 +295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas consumption - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -346,6 +352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas cost - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -400,6 +407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max gas hourly consumption - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -453,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max gas hourly cost - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -506,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max gas hourly energy - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -559,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Min gas hourly consumption - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -612,6 +623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Min gas hourly energy - today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -665,6 +677,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delta energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -718,6 +731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delta volume', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -773,6 +787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -829,6 +844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total volume', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -885,6 +901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy return', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -941,6 +958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -997,6 +1015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy usage high tariff', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1053,6 +1072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy usage low tariff', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1109,6 +1129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1165,6 +1186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cold water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1221,6 +1243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Warm water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/proxmoxve/__init__.py b/tests/components/proxmoxve/__init__.py new file mode 100644 index 00000000000..83468a53823 --- /dev/null +++ b/tests/components/proxmoxve/__init__.py @@ -0,0 +1,26 @@ +"""Tests for Proxmox VE integration.""" + +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.common import MockConfigEntry + + +async def setup_integration( + hass: HomeAssistant, + config_entry: MockConfigEntry, +) -> None: + """Set up the Proxmox VE integration for testing and enable all entities.""" + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + for entry in er.async_entries_for_config_entry( + entity_registry, config_entry.entry_id + ): + if entry.disabled_by is not None: + entity_registry.async_update_entity(entry.entity_id, disabled_by=None) + + await hass.async_block_till_done() diff --git a/tests/components/proxmoxve/conftest.py b/tests/components/proxmoxve/conftest.py new file mode 100644 index 00000000000..7d9405d5064 --- /dev/null +++ b/tests/components/proxmoxve/conftest.py @@ -0,0 +1,142 @@ +"""Common fixtures for the ProxmoxVE tests.""" + +from collections.abc import Generator +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest + +from homeassistant.components.proxmoxve.const import ( + CONF_CONTAINERS, + CONF_NODE, + CONF_NODES, + CONF_REALM, + CONF_VMS, + DOMAIN, +) +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PORT, + CONF_USERNAME, + CONF_VERIFY_SSL, +) + +from tests.common import ( + MockConfigEntry, + load_json_array_fixture, + load_json_object_fixture, +) + +MOCK_TEST_CONFIG = { + CONF_HOST: "127.0.0.1", + CONF_PORT: 8006, + CONF_REALM: "pam", + CONF_USERNAME: "test_user@pam", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + CONF_NODES: [ + { + CONF_NODE: "pve1", + CONF_VMS: [100, 101], + CONF_CONTAINERS: [200, 201], + }, + { + CONF_NODE: "pve2", + CONF_VMS: [100, 101], + CONF_CONTAINERS: [200, 201], + }, + ], +} + + +@pytest.fixture +def mock_setup_entry() -> Generator[AsyncMock]: + """Override async_setup_entry.""" + with patch( + "homeassistant.components.proxmoxve.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + yield mock_setup_entry + + +@pytest.fixture +def mock_proxmox_client(): + """Mock Proxmox client with dynamic exception injection support.""" + with ( + patch( + "homeassistant.components.proxmoxve.ProxmoxAPI", autospec=True + ) as mock_api, + patch( + "homeassistant.components.proxmoxve.common.ProxmoxAPI", autospec=True + ) as mock_api_common, + patch( + "homeassistant.components.proxmoxve.config_flow.ProxmoxAPI" + ) as mock_api_cf, + ): + mock_instance = MagicMock() + mock_api.return_value = mock_instance + mock_api_common.return_value = mock_instance + mock_api_cf.return_value = mock_instance + + mock_instance.access.ticket.post.return_value = load_json_object_fixture( + "access_ticket.json", DOMAIN + ) + + # Make a separate mock for the qemu and lxc endpoints + node_mock = MagicMock() + qemu_list = load_json_array_fixture("nodes/qemu.json", DOMAIN) + lxc_list = load_json_array_fixture("nodes/lxc.json", DOMAIN) + + node_mock.qemu.get.return_value = qemu_list + node_mock.lxc.get.return_value = lxc_list + + qemu_by_vmid = {vm["vmid"]: vm for vm in qemu_list} + lxc_by_vmid = {vm["vmid"]: vm for vm in lxc_list} + + # Note to reviewer: I will expand on these fixtures in a next PR + # Necessary evil to handle the binary_sensor tests properly + def _qemu_resource(vmid: int) -> MagicMock: + """Return a mock resource the QEMU.""" + resource = MagicMock() + vm = qemu_by_vmid[vmid] + resource.status.current.get.return_value = { + "name": vm["name"], + "status": vm["status"], + } + return resource + + def _lxc_resource(vmid: int) -> MagicMock: + """Return a mock resource the LXC.""" + resource = MagicMock() + ct = lxc_by_vmid[vmid] + resource.status.current.get.return_value = { + "name": ct["name"], + "status": ct["status"], + } + return resource + + node_mock.qemu.side_effect = _qemu_resource + node_mock.lxc.side_effect = _lxc_resource + + nodes_mock = MagicMock() + nodes_mock.get.return_value = load_json_array_fixture( + "nodes/nodes.json", DOMAIN + ) + nodes_mock.__getitem__.side_effect = lambda key: node_mock + nodes_mock.return_value = node_mock + + mock_instance.nodes = nodes_mock + mock_instance._node_mock = node_mock + mock_instance._nodes_mock = nodes_mock + + yield mock_instance + + +@pytest.fixture +def mock_config_entry() -> MockConfigEntry: + """Mock a config entry.""" + return MockConfigEntry( + domain=DOMAIN, + title="ProxmoxVE test", + data=MOCK_TEST_CONFIG, + ) diff --git a/tests/components/proxmoxve/fixtures/access_ticket.json b/tests/components/proxmoxve/fixtures/access_ticket.json new file mode 100644 index 00000000000..c94d805c325 --- /dev/null +++ b/tests/components/proxmoxve/fixtures/access_ticket.json @@ -0,0 +1,5 @@ +{ + "username": "test_user@pam", + "ticket": "test_ticket", + "CSRFPreventionToken": "test_token" +} diff --git a/tests/components/proxmoxve/fixtures/nodes/lxc.json b/tests/components/proxmoxve/fixtures/nodes/lxc.json new file mode 100644 index 00000000000..0dd378ad9f8 --- /dev/null +++ b/tests/components/proxmoxve/fixtures/nodes/lxc.json @@ -0,0 +1,18 @@ +[ + { + "vmid": 200, + "name": "ct-nginx", + "status": "running", + "maxmem": 1073741824, + "mem": 536870912, + "cpu": 0.05, + "maxdisk": 21474836480, + "disk": 1125899906, + "uptime": 43200 + }, + { + "vmid": 201, + "name": "ct-backup", + "status": "stopped" + } +] diff --git a/tests/components/proxmoxve/fixtures/nodes/nodes.json b/tests/components/proxmoxve/fixtures/nodes/nodes.json new file mode 100644 index 00000000000..17e85c0567a --- /dev/null +++ b/tests/components/proxmoxve/fixtures/nodes/nodes.json @@ -0,0 +1,32 @@ +[ + { + "id": "node/pve1", + "node": "pve1", + "status": "online", + "level": "", + "type": "node", + "maxmem": 34359738368, + "mem": 12884901888, + "maxcpu": 8, + "cpu": 0.12, + "uptime": 86400, + "maxdisk": 500000000000, + "disk": 100000000000, + "ssl_fingerprint": "5C:D2:AB:...:D9" + }, + { + "id": "node/pve2", + "node": "pve2", + "status": "online", + "level": "", + "type": "node", + "maxmem": 34359738368, + "mem": 16106127360, + "maxcpu": 8, + "cpu": 0.25, + "uptime": 72000, + "maxdisk": 500000000000, + "disk": 120000000000, + "ssl_fingerprint": "7A:E1:DF:...:AC" + } +] diff --git a/tests/components/proxmoxve/fixtures/nodes/qemu.json b/tests/components/proxmoxve/fixtures/nodes/qemu.json new file mode 100644 index 00000000000..e1b51d88df1 --- /dev/null +++ b/tests/components/proxmoxve/fixtures/nodes/qemu.json @@ -0,0 +1,18 @@ +[ + { + "vmid": 100, + "name": "vm-web", + "status": "running", + "maxmem": 2147483648, + "mem": 1073741824, + "cpu": 0.15, + "maxdisk": 34359738368, + "disk": 1234567890, + "uptime": 86400 + }, + { + "vmid": 101, + "name": "vm-db", + "status": "stopped" + } +] diff --git a/tests/components/proxmoxve/snapshots/test_binary_sensor.ambr b/tests/components/proxmoxve/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..81a6710d8d1 --- /dev/null +++ b/tests/components/proxmoxve/snapshots/test_binary_sensor.ambr @@ -0,0 +1,409 @@ +# serializer version: 1 +# name: test_all_entities[binary_sensor.pve1_ct_backup-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve1_ct_backup', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve1_ct-backup', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve1_ct-backup', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve1_201_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve1_ct_backup-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve1_ct-backup', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve1_ct_backup', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_all_entities[binary_sensor.pve1_ct_nginx-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve1_ct_nginx', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve1_ct-nginx', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve1_ct-nginx', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve1_200_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve1_ct_nginx-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve1_ct-nginx', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve1_ct_nginx', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_all_entities[binary_sensor.pve1_vm_db-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve1_vm_db', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve1_vm-db', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve1_vm-db', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve1_101_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve1_vm_db-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve1_vm-db', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve1_vm_db', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_all_entities[binary_sensor.pve1_vm_web-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve1_vm_web', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve1_vm-web', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve1_vm-web', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve1_100_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve1_vm_web-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve1_vm-web', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve1_vm_web', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_all_entities[binary_sensor.pve2_ct_backup-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve2_ct_backup', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve2_ct-backup', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve2_ct-backup', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve2_201_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve2_ct_backup-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve2_ct-backup', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve2_ct_backup', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_all_entities[binary_sensor.pve2_ct_nginx-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve2_ct_nginx', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve2_ct-nginx', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve2_ct-nginx', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve2_200_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve2_ct_nginx-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve2_ct-nginx', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve2_ct_nginx', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_all_entities[binary_sensor.pve2_vm_db-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve2_vm_db', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve2_vm-db', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve2_vm-db', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve2_101_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve2_vm_db-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve2_vm-db', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve2_vm_db', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_all_entities[binary_sensor.pve2_vm_web-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pve2_vm_web', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'pve2_vm-web', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': '', + 'original_name': 'pve2_vm-web', + 'platform': 'proxmoxve', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'proxmox_pve2_100_running', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.pve2_vm_web-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'pve2_vm-web', + 'icon': '', + }), + 'context': , + 'entity_id': 'binary_sensor.pve2_vm_web', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- diff --git a/tests/components/proxmoxve/test_binary_sensor.py b/tests/components/proxmoxve/test_binary_sensor.py new file mode 100644 index 00000000000..0f16eedfc85 --- /dev/null +++ b/tests/components/proxmoxve/test_binary_sensor.py @@ -0,0 +1,33 @@ +"""Test the Proxmox VE binary sensor platform.""" + +from unittest.mock import MagicMock, patch + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +import homeassistant.helpers.entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +async def test_all_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + mock_proxmox_client: MagicMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test all entities.""" + with patch( + "homeassistant.components.proxmoxve.PLATFORMS", + [Platform.BINARY_SENSOR], + ): + await setup_integration(hass, mock_config_entry) + await snapshot_platform( + hass, entity_registry, snapshot, mock_config_entry.entry_id + ) diff --git a/tests/components/proxmoxve/test_config_flow.py b/tests/components/proxmoxve/test_config_flow.py new file mode 100644 index 00000000000..2e6ee6d93c9 --- /dev/null +++ b/tests/components/proxmoxve/test_config_flow.py @@ -0,0 +1,230 @@ +"""Test the config flow for Proxmox VE.""" + +from __future__ import annotations + +from unittest.mock import MagicMock + +from proxmoxer import AuthenticationError +import pytest +from requests.exceptions import ConnectTimeout, SSLError + +from homeassistant.components.proxmoxve import CONF_HOST, CONF_REALM +from homeassistant.components.proxmoxve.common import ResourceException +from homeassistant.components.proxmoxve.const import CONF_NODES, DOMAIN +from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, ConfigEntryState +from homeassistant.const import CONF_PASSWORD, CONF_PORT, CONF_USERNAME, CONF_VERIFY_SSL +from homeassistant.core import HomeAssistant +from homeassistant.data_entry_flow import FlowResultType + +from .conftest import MOCK_TEST_CONFIG + +from tests.common import MockConfigEntry + +MOCK_USER_STEP = { + CONF_HOST: "127.0.0.1", + CONF_USERNAME: "test_user@pam", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + CONF_PORT: 8006, + CONF_REALM: "pam", +} + +MOCK_USER_SETUP = {CONF_NODES: ["pve1"]} + +MOCK_USER_FINAL = { + **MOCK_USER_STEP, + **MOCK_USER_SETUP, +} + + +async def test_form( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, +) -> None: + """Test we get the form.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=MOCK_USER_STEP + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "127.0.0.1" + assert result["data"] == MOCK_TEST_CONFIG + + +@pytest.mark.parametrize( + ("exception", "reason"), + [ + ( + AuthenticationError("Invalid credentials"), + "invalid_auth", + ), + ( + SSLError("SSL handshake failed"), + "ssl_error", + ), + ( + ConnectTimeout("Connection timed out"), + "connect_timeout", + ), + ], +) +async def test_form_exceptions( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, + exception: Exception, + reason: str, +) -> None: + """Test we handle all exceptions.""" + mock_proxmox_client.nodes.get.side_effect = exception + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=MOCK_USER_STEP, + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": reason} + + mock_proxmox_client.nodes.get.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=MOCK_USER_STEP + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + + +async def test_form_no_nodes_exception( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, +) -> None: + """Test we handle no nodes found exception.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + mock_proxmox_client.nodes.get.side_effect = ResourceException( + "404", "status_message", "content" + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=MOCK_USER_STEP + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": "no_nodes_found"} + + mock_proxmox_client.nodes.get.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=MOCK_USER_STEP + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + + +async def test_duplicate_entry( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, + mock_setup_entry: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test we handle duplicate entries.""" + mock_config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input=MOCK_USER_STEP + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + +async def test_import_flow( + hass: HomeAssistant, + mock_setup_entry: MagicMock, + mock_proxmox_client: MagicMock, +) -> None: + """Test importing from YAML creates a config entry and sets it up.""" + MOCK_IMPORT_CONFIG = { + DOMAIN: { + **MOCK_USER_STEP, + **MOCK_USER_SETUP, + } + } + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=MOCK_IMPORT_CONFIG[DOMAIN] + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "127.0.0.1" + assert result["data"][CONF_HOST] == "127.0.0.1" + assert len(mock_setup_entry.mock_calls) == 1 + + assert result["result"].state is ConfigEntryState.LOADED + + +@pytest.mark.parametrize( + ("exception", "reason"), + [ + ( + AuthenticationError("Invalid credentials"), + "invalid_auth", + ), + ( + SSLError("SSL handshake failed"), + "ssl_error", + ), + ( + ConnectTimeout("Connection timed out"), + "connect_timeout", + ), + ( + ResourceException("404", "status_message", "content"), + "no_nodes_found", + ), + ], +) +async def test_import_flow_exceptions( + hass: HomeAssistant, + mock_setup_entry: MagicMock, + mock_proxmox_client: MagicMock, + exception: Exception, + reason: str, +) -> None: + """Test importing from YAML creates a config entry and sets it up.""" + MOCK_IMPORT_CONFIG = { + DOMAIN: { + **MOCK_USER_STEP, + **MOCK_USER_SETUP, + } + } + mock_proxmox_client.nodes.get.side_effect = exception + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=MOCK_IMPORT_CONFIG[DOMAIN] + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == reason + assert len(mock_setup_entry.mock_calls) == 0 + assert len(hass.config_entries.async_entries(DOMAIN)) == 0 diff --git a/tests/components/proxmoxve/test_init.py b/tests/components/proxmoxve/test_init.py new file mode 100644 index 00000000000..1b6b7449cca --- /dev/null +++ b/tests/components/proxmoxve/test_init.py @@ -0,0 +1,60 @@ +"""Tests for the Proxmox VE integration initialization.""" + +from unittest.mock import MagicMock + +from homeassistant.components.proxmoxve.const import ( + CONF_CONTAINERS, + CONF_NODE, + CONF_NODES, + CONF_REALM, + CONF_VMS, + DOMAIN, +) +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PORT, + CONF_USERNAME, + CONF_VERIFY_SSL, +) +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant +import homeassistant.helpers.issue_registry as ir +from homeassistant.setup import async_setup_component + + +async def test_config_import( + hass: HomeAssistant, + mock_proxmox_client: MagicMock, + mock_setup_entry: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test sensor initialization.""" + await async_setup_component( + hass, + DOMAIN, + { + DOMAIN: [ + { + CONF_HOST: "127.0.0.1", + CONF_PORT: 8006, + CONF_REALM: "pam", + CONF_USERNAME: "test_user@pam", + CONF_PASSWORD: "test_password", + CONF_VERIFY_SSL: True, + CONF_NODES: [ + { + CONF_NODE: "pve1", + CONF_VMS: [100, 101], + CONF_CONTAINERS: [200, 201], + }, + ], + } + ] + }, + ) + + await hass.async_block_till_done() + + assert len(issue_registry.issues) == 1 + assert (HOMEASSISTANT_DOMAIN, "deprecated_yaml") in issue_registry.issues + assert len(hass.config_entries.async_entries(DOMAIN)) == 1 diff --git a/tests/components/pterodactyl/snapshots/test_binary_sensor.ambr b/tests/components/pterodactyl/snapshots/test_binary_sensor.ambr index f9f6cbfc44f..941d47fa6b4 100644 --- a/tests/components/pterodactyl/snapshots/test_binary_sensor.ambr +++ b/tests/components/pterodactyl/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/pyload/snapshots/test_button.ambr b/tests/components/pyload/snapshots/test_button.ambr index 4cc5bd42e6c..57f820c76b4 100644 --- a/tests/components/pyload/snapshots/test_button.ambr +++ b/tests/components/pyload/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Abort all running downloads', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delete finished files/packages', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart all failed files', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart pyload core', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/pyload/snapshots/test_sensor.ambr b/tests/components/pyload/snapshots/test_sensor.ambr index ce2b822a6aa..4a83f01278d 100644 --- a/tests/components/pyload/snapshots/test_sensor.ambr +++ b/tests/components/pyload/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active downloads', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Downloads in queue', 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -238,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total downloads', 'options': dict({ }), 'original_device_class': None, @@ -290,6 +295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active downloads', 'options': dict({ }), 'original_device_class': None, @@ -342,6 +348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Downloads in queue', 'options': dict({ }), 'original_device_class': None, @@ -392,6 +399,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -448,6 +456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -506,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total downloads', 'options': dict({ }), 'original_device_class': None, @@ -558,6 +568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active downloads', 'options': dict({ }), 'original_device_class': None, @@ -610,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Downloads in queue', 'options': dict({ }), 'original_device_class': None, @@ -660,6 +672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -716,6 +729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -774,6 +788,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total downloads', 'options': dict({ }), 'original_device_class': None, @@ -826,6 +841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active downloads', 'options': dict({ }), 'original_device_class': None, @@ -878,6 +894,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Downloads in queue', 'options': dict({ }), 'original_device_class': None, @@ -928,6 +945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -984,6 +1002,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1042,6 +1061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total downloads', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/pyload/snapshots/test_switch.ambr b/tests/components/pyload/snapshots/test_switch.ambr index b1f566fc8c8..8023b3e7ee5 100644 --- a/tests/components/pyload/snapshots/test_switch.ambr +++ b/tests/components/pyload/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-Reconnect', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause/Resume queue', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/qbittorrent/snapshots/test_sensor.ambr b/tests/components/qbittorrent/snapshots/test_sensor.ambr index 2f1cfe985ed..b8d98fdecc6 100644 --- a/tests/components/qbittorrent/snapshots/test_sensor.ambr +++ b/tests/components/qbittorrent/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active torrents', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All-time download', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All-time upload', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'All torrents', 'options': dict({ }), 'original_device_class': None, @@ -242,6 +246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection status', 'options': dict({ }), 'original_device_class': , @@ -298,6 +303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Download speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -357,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Download speed limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Errored torrents', 'options': dict({ }), 'original_device_class': None, @@ -465,6 +473,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Global ratio', 'options': dict({ }), 'original_device_class': None, @@ -514,6 +523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inactive torrents', 'options': dict({ }), 'original_device_class': None, @@ -563,6 +573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Paused torrents', 'options': dict({ }), 'original_device_class': None, @@ -619,6 +630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -676,6 +688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upload speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -735,6 +748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upload speed limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/qbus/snapshots/test_binary_sensor.ambr b/tests/components/qbus/snapshots/test_binary_sensor.ambr index 79b36db6639..8f193245e7b 100644 --- a/tests/components/qbus/snapshots/test_binary_sensor.ambr +++ b/tests/components/qbus/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Raining', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Twilight', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/qbus/snapshots/test_sensor.ambr b/tests/components/qbus/snapshots/test_sensor.ambr index fe665057b1e..97541ec9071 100644 --- a/tests/components/qbus/snapshots/test_sensor.ambr +++ b/tests/components/qbus/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -635,6 +646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -691,6 +703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -747,6 +760,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daylight', 'options': dict({ }), 'original_device_class': , @@ -800,6 +814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -853,6 +868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance east', 'options': dict({ }), 'original_device_class': , @@ -906,6 +922,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance south', 'options': dict({ }), 'original_device_class': , @@ -959,6 +976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance west', 'options': dict({ }), 'original_device_class': , @@ -1012,6 +1030,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/rainforest_raven/snapshots/test_sensor.ambr b/tests/components/rainforest_raven/snapshots/test_sensor.ambr index 340248f6d8b..6a1c9be3067 100644 --- a/tests/components/rainforest_raven/snapshots/test_sensor.ambr +++ b/tests/components/rainforest_raven/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy price', 'options': dict({ }), 'original_device_class': None, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power demand', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -185,6 +188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy delivered', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -241,6 +245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy received', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/rainmachine/snapshots/test_binary_sensor.ambr b/tests/components/rainmachine/snapshots/test_binary_sensor.ambr index 1e7e15f2a49..663b0818171 100644 --- a/tests/components/rainmachine/snapshots/test_binary_sensor.ambr +++ b/tests/components/rainmachine/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freeze restrictions', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hourly restrictions', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Month restrictions', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain delay restrictions', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain sensor restrictions', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekday restrictions', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/rainmachine/snapshots/test_button.ambr b/tests/components/rainmachine/snapshots/test_button.ambr index 8126c190a8d..436153512ee 100644 --- a/tests/components/rainmachine/snapshots/test_button.ambr +++ b/tests/components/rainmachine/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/rainmachine/snapshots/test_select.ambr b/tests/components/rainmachine/snapshots/test_select.ambr index 4b4ba86bb2e..58796b59730 100644 --- a/tests/components/rainmachine/snapshots/test_select.ambr +++ b/tests/components/rainmachine/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freeze protection temperature', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/rainmachine/snapshots/test_sensor.ambr b/tests/components/rainmachine/snapshots/test_sensor.ambr index 4b9c98483ae..668d21daa76 100644 --- a/tests/components/rainmachine/snapshots/test_sensor.ambr +++ b/tests/components/rainmachine/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evening Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flower Box Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Landscaping Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Morning Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain sensor rain start', 'options': dict({ }), 'original_device_class': , @@ -266,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TEST Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -315,6 +321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 10 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -364,6 +371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 11 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -413,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 12 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -462,6 +471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 4 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -511,6 +521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 5 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -560,6 +571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 6 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -609,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 7 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -658,6 +671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 8 Run Completion Time', 'options': dict({ }), 'original_device_class': , @@ -707,6 +721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 9 Run Completion Time', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/rainmachine/snapshots/test_switch.ambr b/tests/components/rainmachine/snapshots/test_switch.ambr index 5ef256bc408..63aef1db174 100644 --- a/tests/components/rainmachine/snapshots/test_switch.ambr +++ b/tests/components/rainmachine/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evening', 'options': dict({ }), 'original_device_class': None, @@ -94,6 +95,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evening enabled', 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extra water on hot days', 'options': dict({ }), 'original_device_class': None, @@ -193,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flower box', 'options': dict({ }), 'original_device_class': None, @@ -256,6 +260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flower box enabled', 'options': dict({ }), 'original_device_class': None, @@ -306,6 +311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freeze protection', 'options': dict({ }), 'original_device_class': None, @@ -355,6 +361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Landscaping', 'options': dict({ }), 'original_device_class': None, @@ -418,6 +425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Landscaping enabled', 'options': dict({ }), 'original_device_class': None, @@ -468,6 +476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Morning', 'options': dict({ }), 'original_device_class': None, @@ -542,6 +551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Morning enabled', 'options': dict({ }), 'original_device_class': None, @@ -592,6 +602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test', 'options': dict({ }), 'original_device_class': None, @@ -655,6 +666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test enabled', 'options': dict({ }), 'original_device_class': None, @@ -705,6 +717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 10', 'options': dict({ }), 'original_device_class': None, @@ -768,6 +781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 10 enabled', 'options': dict({ }), 'original_device_class': None, @@ -818,6 +832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 11', 'options': dict({ }), 'original_device_class': None, @@ -881,6 +896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 11 enabled', 'options': dict({ }), 'original_device_class': None, @@ -931,6 +947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 12', 'options': dict({ }), 'original_device_class': None, @@ -994,6 +1011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 12 enabled', 'options': dict({ }), 'original_device_class': None, @@ -1044,6 +1062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 4', 'options': dict({ }), 'original_device_class': None, @@ -1107,6 +1126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 4 enabled', 'options': dict({ }), 'original_device_class': None, @@ -1157,6 +1177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 5', 'options': dict({ }), 'original_device_class': None, @@ -1220,6 +1241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 5 enabled', 'options': dict({ }), 'original_device_class': None, @@ -1270,6 +1292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 6', 'options': dict({ }), 'original_device_class': None, @@ -1333,6 +1356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 6 enabled', 'options': dict({ }), 'original_device_class': None, @@ -1383,6 +1407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 7', 'options': dict({ }), 'original_device_class': None, @@ -1446,6 +1471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 7 enabled', 'options': dict({ }), 'original_device_class': None, @@ -1496,6 +1522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 8', 'options': dict({ }), 'original_device_class': None, @@ -1559,6 +1586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 8 enabled', 'options': dict({ }), 'original_device_class': None, @@ -1609,6 +1637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 9', 'options': dict({ }), 'original_device_class': None, @@ -1672,6 +1701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 9 enabled', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/rehlko/snapshots/test_binary_sensor.ambr b/tests/components/rehlko/snapshots/test_binary_sensor.ambr index 38b5b048d08..94df32958fa 100644 --- a/tests/components/rehlko/snapshots/test_binary_sensor.ambr +++ b/tests/components/rehlko/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto run', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil pressure', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/rehlko/snapshots/test_sensor.ambr b/tests/components/rehlko/snapshots/test_sensor.ambr index d20b916d3ea..f748e272afa 100644 --- a/tests/components/rehlko/snapshots/test_sensor.ambr +++ b/tests/components/rehlko/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Controller temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device IP address', 'options': dict({ }), 'original_device_class': None, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine compartment temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -238,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine coolant temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -294,6 +299,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -350,6 +356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine oil pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -409,6 +416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine speed', 'options': dict({ }), 'original_device_class': None, @@ -459,6 +467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine state', 'options': dict({ }), 'original_device_class': None, @@ -509,6 +518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator load', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -565,6 +575,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator load percentage', 'options': dict({ }), 'original_device_class': None, @@ -615,6 +626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator status', 'options': dict({ }), 'original_device_class': None, @@ -663,6 +675,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last exercise', 'options': dict({ }), 'original_device_class': , @@ -712,6 +725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last maintainance', 'options': dict({ }), 'original_device_class': , @@ -761,6 +775,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last run', 'options': dict({ }), 'original_device_class': , @@ -812,6 +827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lube oil temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -866,6 +882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next exercise', 'options': dict({ }), 'original_device_class': , @@ -915,6 +932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next maintainance', 'options': dict({ }), 'original_device_class': , @@ -964,6 +982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power source', 'options': dict({ }), 'original_device_class': None, @@ -1014,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Runtime since last maintenance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1068,6 +1088,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Server IP address', 'options': dict({ }), 'original_device_class': None, @@ -1118,6 +1139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total operation', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1174,6 +1196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total runtime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1230,6 +1253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Utility voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1286,6 +1310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/remote/test_device_action.py b/tests/components/remote/test_device_action.py index e224fcf4939..34cc74b1506 100644 --- a/tests/components/remote/test_device_action.py +++ b/tests/components/remote/test_device_action.py @@ -19,11 +19,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/remote/test_device_condition.py b/tests/components/remote/test_device_condition.py index c5ba1c77c31..efa3ae4709c 100644 --- a/tests/components/remote/test_device_condition.py +++ b/tests/components/remote/test_device_condition.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/remote/test_device_trigger.py b/tests/components/remote/test_device_trigger.py index 0321ba8bbaa..cc4a6602d3b 100644 --- a/tests/components/remote/test_device_trigger.py +++ b/tests/components/remote/test_device_trigger.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/renault/snapshots/test_binary_sensor.ambr b/tests/components/renault/snapshots/test_binary_sensor.ambr index 10537d48064..13a158ce030 100644 --- a/tests/components/renault/snapshots/test_binary_sensor.ambr +++ b/tests/components/renault/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -360,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -409,6 +417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -457,6 +466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -506,6 +516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -555,6 +566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -603,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -652,6 +665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -701,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -749,6 +764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , @@ -798,6 +814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -847,6 +864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC', 'options': dict({ }), 'original_device_class': None, @@ -895,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/renault/snapshots/test_button.ambr b/tests/components/renault/snapshots/test_button.ambr index 95e81aee4c5..177b5f2ceb5 100644 --- a/tests/components/renault/snapshots/test_button.ambr +++ b/tests/components/renault/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -692,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -740,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -836,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -884,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -932,6 +951,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -980,6 +1000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -1028,6 +1049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, @@ -1076,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start air conditioner', 'options': dict({ }), 'original_device_class': None, @@ -1124,6 +1147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start charge', 'options': dict({ }), 'original_device_class': None, @@ -1172,6 +1196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop charge', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/renault/snapshots/test_device_tracker.ambr b/tests/components/renault/snapshots/test_device_tracker.ambr index 15f95140a8f..656c8c906f2 100644 --- a/tests/components/renault/snapshots/test_device_tracker.ambr +++ b/tests/components/renault/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -169,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -221,6 +225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -273,6 +278,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/renault/snapshots/test_select.ambr b/tests/components/renault/snapshots/test_select.ambr index ffcefb2ca5d..89e85befdbf 100644 --- a/tests/components/renault/snapshots/test_select.ambr +++ b/tests/components/renault/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge mode', 'options': dict({ }), 'original_device_class': None, @@ -88,6 +89,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge mode', 'options': dict({ }), 'original_device_class': None, @@ -149,6 +151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/renault/snapshots/test_sensor.ambr b/tests/components/renault/snapshots/test_sensor.ambr index 8e05d6e246e..3e0cc9b7a8f 100644 --- a/tests/components/renault/snapshots/test_sensor.ambr +++ b/tests/components/renault/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery available energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -252,6 +256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge state', 'options': dict({ }), 'original_device_class': , @@ -313,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -369,6 +375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -423,6 +430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -472,6 +480,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last battery activity', 'options': dict({ }), 'original_device_class': , @@ -521,6 +530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -572,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -628,6 +639,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -690,6 +702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug state', 'options': dict({ }), 'original_device_class': , @@ -748,6 +761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -801,6 +815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -857,6 +872,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery available energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -913,6 +929,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -978,6 +995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge state', 'options': dict({ }), 'original_device_class': , @@ -1039,6 +1057,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1095,6 +1114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1149,6 +1169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -1198,6 +1219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last battery activity', 'options': dict({ }), 'original_device_class': , @@ -1247,6 +1269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -1298,6 +1321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1354,6 +1378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1416,6 +1441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug state', 'options': dict({ }), 'original_device_class': , @@ -1474,6 +1500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1530,6 +1557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel quantity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1584,6 +1612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -1633,6 +1662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -1682,6 +1712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last location activity', 'options': dict({ }), 'original_device_class': , @@ -1733,6 +1764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1789,6 +1821,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1845,6 +1878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Admissible charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1901,6 +1935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1954,6 +1989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2010,6 +2046,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery available energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2066,6 +2103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2131,6 +2169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge state', 'options': dict({ }), 'original_device_class': , @@ -2192,6 +2231,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2248,6 +2288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2304,6 +2345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel quantity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2358,6 +2400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -2407,6 +2450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last battery activity', 'options': dict({ }), 'original_device_class': , @@ -2456,6 +2500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -2505,6 +2550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last location activity', 'options': dict({ }), 'original_device_class': , @@ -2556,6 +2602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2612,6 +2659,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2674,6 +2722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug state', 'options': dict({ }), 'original_device_class': , @@ -2732,6 +2781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Admissible charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2788,6 +2838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2841,6 +2892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2897,6 +2949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery available energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2953,6 +3006,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3018,6 +3072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge state', 'options': dict({ }), 'original_device_class': , @@ -3079,6 +3134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3133,6 +3189,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -3182,6 +3239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last battery activity', 'options': dict({ }), 'original_device_class': , @@ -3231,6 +3289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -3280,6 +3339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last location activity', 'options': dict({ }), 'original_device_class': , @@ -3331,6 +3391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3387,6 +3448,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3449,6 +3511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug state', 'options': dict({ }), 'original_device_class': , @@ -3507,6 +3570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3560,6 +3624,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3616,6 +3681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery available energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3672,6 +3738,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3737,6 +3804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge state', 'options': dict({ }), 'original_device_class': , @@ -3798,6 +3866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3854,6 +3923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3908,6 +3978,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -3957,6 +4028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last battery activity', 'options': dict({ }), 'original_device_class': , @@ -4006,6 +4078,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -4057,6 +4130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4113,6 +4187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4175,6 +4250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug state', 'options': dict({ }), 'original_device_class': , @@ -4233,6 +4309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Admissible charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4289,6 +4366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4342,6 +4420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery autonomy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4398,6 +4477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery available energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4454,6 +4534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4519,6 +4600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge state', 'options': dict({ }), 'original_device_class': , @@ -4580,6 +4662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging remaining time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4636,6 +4719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front left tyre pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4692,6 +4776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front right tyre pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4746,6 +4831,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'HVAC SoC threshold', 'options': dict({ }), 'original_device_class': None, @@ -4795,6 +4881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last battery activity', 'options': dict({ }), 'original_device_class': , @@ -4844,6 +4931,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last HVAC activity', 'options': dict({ }), 'original_device_class': , @@ -4893,6 +4981,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last location activity', 'options': dict({ }), 'original_device_class': , @@ -4944,6 +5033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mileage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5000,6 +5090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5062,6 +5153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plug state', 'options': dict({ }), 'original_device_class': , @@ -5120,6 +5212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear left tyre pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5176,6 +5269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear right tyre pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/ridwell/test_calendar.py b/tests/components/ridwell/test_calendar.py index 811455a7ee3..e0fd36aa077 100644 --- a/tests/components/ridwell/test_calendar.py +++ b/tests/components/ridwell/test_calendar.py @@ -21,7 +21,6 @@ START_DATE = date(2025, 10, 4) END_DATE = date(2025, 10, 5) -@pytest.mark.asyncio @pytest.mark.parametrize( ( "pickup_name", diff --git a/tests/components/ring/snapshots/test_binary_sensor.ambr b/tests/components/ring/snapshots/test_binary_sensor.ambr index 9fa57800ec9..1c05083ae91 100644 --- a/tests/components/ring/snapshots/test_binary_sensor.ambr +++ b/tests/components/ring/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ding', 'options': dict({ }), 'original_device_class': , @@ -27,7 +28,7 @@ 'original_name': 'Ding', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_ding', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'ding', 'unique_id': '987654-ding', @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -77,7 +79,7 @@ 'original_name': 'Motion', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_motion', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '987654-motion', @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -127,7 +130,7 @@ 'original_name': 'Motion', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_motion', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '765432-motion', @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ding', 'options': dict({ }), 'original_device_class': , @@ -177,7 +181,7 @@ 'original_name': 'Ding', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'ingress_ding', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'ding', 'unique_id': '185036587-ding', @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -227,7 +232,7 @@ 'original_name': 'Motion', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'internal_motion', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '345678-motion', diff --git a/tests/components/ring/snapshots/test_button.ambr b/tests/components/ring/snapshots/test_button.ambr index fe9afb7964e..a6538a39532 100644 --- a/tests/components/ring/snapshots/test_button.ambr +++ b/tests/components/ring/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Open door', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ring/snapshots/test_camera.ambr b/tests/components/ring/snapshots/test_camera.ambr index bc0ecbdc794..8ba1d498f7a 100644 --- a/tests/components/ring/snapshots/test_camera.ambr +++ b/tests/components/ring/snapshots/test_camera.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last recording', 'options': dict({ }), 'original_device_class': None, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Live view', 'options': dict({ }), 'original_device_class': None, @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last recording', 'options': dict({ }), 'original_device_class': None, @@ -183,6 +186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Live view', 'options': dict({ }), 'original_device_class': None, @@ -237,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last recording', 'options': dict({ }), 'original_device_class': None, @@ -292,6 +297,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Live view', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ring/snapshots/test_event.ambr b/tests/components/ring/snapshots/test_event.ambr index f1d2d2fd09f..10a1422defc 100644 --- a/tests/components/ring/snapshots/test_event.ambr +++ b/tests/components/ring/snapshots/test_event.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ding', 'options': dict({ }), 'original_device_class': , @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -198,6 +201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ding', 'options': dict({ }), 'original_device_class': , @@ -256,6 +260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intercom unlock', 'options': dict({ }), 'original_device_class': , @@ -314,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/ring/snapshots/test_light.ambr b/tests/components/ring/snapshots/test_light.ambr index 8727adbb6e2..5037813aa3d 100644 --- a/tests/components/ring/snapshots/test_light.ambr +++ b/tests/components/ring/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ring/snapshots/test_number.ambr b/tests/components/ring/snapshots/test_number.ambr index b32a97f71d2..cf309439d7b 100644 --- a/tests/components/ring/snapshots/test_number.ambr +++ b/tests/components/ring/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell volume', 'options': dict({ }), 'original_device_class': None, @@ -257,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mic volume', 'options': dict({ }), 'original_device_class': None, @@ -315,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voice volume', 'options': dict({ }), 'original_device_class': None, @@ -373,6 +379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ring/snapshots/test_sensor.ambr b/tests/components/ring/snapshots/test_sensor.ambr index 249a47548b8..8cd845f9fbb 100644 --- a/tests/components/ring/snapshots/test_sensor.ambr +++ b/tests/components/ring/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -27,7 +28,7 @@ 'original_name': 'Volume', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'downstairs_volume', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'volume', 'unique_id': '123456-volume', @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi signal category', 'options': dict({ }), 'original_device_class': None, @@ -76,7 +78,7 @@ 'original_name': 'Wi-Fi signal category', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'downstairs_wifi_signal_category', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'wifi_signal_category', 'unique_id': '123456-wifi_signal_category', @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -125,7 +128,7 @@ 'original_name': 'Signal strength', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'downstairs_wifi_signal_strength', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '123456-wifi_signal_strength', @@ -171,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -225,6 +229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -277,6 +282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last activity', 'options': dict({ }), 'original_device_class': , @@ -327,6 +333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last ding', 'options': dict({ }), 'original_device_class': , @@ -334,7 +341,7 @@ 'original_name': 'Last ding', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_last_ding', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'last_ding', 'unique_id': '987654-last_ding', @@ -377,6 +384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last motion', 'options': dict({ }), 'original_device_class': , @@ -384,7 +392,7 @@ 'original_name': 'Last motion', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_last_motion', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'last_motion', 'unique_id': '987654-last_motion', @@ -427,6 +435,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -434,7 +443,7 @@ 'original_name': 'Volume', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_volume', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'volume', 'unique_id': '765432-volume', @@ -476,6 +485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi signal category', 'options': dict({ }), 'original_device_class': None, @@ -483,7 +493,7 @@ 'original_name': 'Wi-Fi signal category', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_wifi_signal_category', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'wifi_signal_category', 'unique_id': '987654-wifi_signal_category', @@ -525,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -532,7 +543,7 @@ 'original_name': 'Signal strength', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_door_wifi_signal_strength', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '987654-wifi_signal_strength', @@ -576,6 +587,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last activity', 'options': dict({ }), 'original_device_class': , @@ -626,6 +638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last ding', 'options': dict({ }), 'original_device_class': , @@ -633,7 +646,7 @@ 'original_name': 'Last ding', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_last_ding', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'last_ding', 'unique_id': '765432-last_ding', @@ -676,6 +689,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last motion', 'options': dict({ }), 'original_device_class': , @@ -683,7 +697,7 @@ 'original_name': 'Last motion', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_last_motion', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'last_motion', 'unique_id': '765432-last_motion', @@ -726,6 +740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi signal category', 'options': dict({ }), 'original_device_class': None, @@ -733,7 +748,7 @@ 'original_name': 'Wi-Fi signal category', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_wifi_signal_category', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'wifi_signal_category', 'unique_id': '765432-wifi_signal_category', @@ -775,6 +790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -782,7 +798,7 @@ 'original_name': 'Signal strength', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_wifi_signal_strength', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '765432-wifi_signal_strength', @@ -828,6 +844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -880,6 +897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell volume', 'options': dict({ }), 'original_device_class': None, @@ -887,7 +905,7 @@ 'original_name': 'Doorbell volume', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'ingress_doorbell_volume', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'doorbell_volume', 'unique_id': '185036587-doorbell_volume', @@ -929,6 +947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last activity', 'options': dict({ }), 'original_device_class': , @@ -979,6 +998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mic volume', 'options': dict({ }), 'original_device_class': None, @@ -986,7 +1006,7 @@ 'original_name': 'Mic volume', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'ingress_mic_volume', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'mic_volume', 'unique_id': '185036587-mic_volume', @@ -1028,6 +1048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voice volume', 'options': dict({ }), 'original_device_class': None, @@ -1035,7 +1056,7 @@ 'original_name': 'Voice volume', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'ingress_voice_volume', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'voice_volume', 'unique_id': '185036587-voice_volume', @@ -1077,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi signal category', 'options': dict({ }), 'original_device_class': None, @@ -1084,7 +1106,7 @@ 'original_name': 'Wi-Fi signal category', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'ingress_wifi_signal_category', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'wifi_signal_category', 'unique_id': '185036587-wifi_signal_category', @@ -1126,6 +1148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1133,7 +1156,7 @@ 'original_name': 'Signal strength', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'ingress_wifi_signal_strength', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '185036587-wifi_signal_strength', @@ -1179,6 +1202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1231,6 +1255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last activity', 'options': dict({ }), 'original_device_class': , @@ -1281,6 +1306,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last ding', 'options': dict({ }), 'original_device_class': , @@ -1288,7 +1314,7 @@ 'original_name': 'Last ding', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'internal_last_ding', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'last_ding', 'unique_id': '345678-last_ding', @@ -1331,6 +1357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last motion', 'options': dict({ }), 'original_device_class': , @@ -1338,7 +1365,7 @@ 'original_name': 'Last motion', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'internal_last_motion', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'last_motion', 'unique_id': '345678-last_motion', @@ -1381,6 +1408,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi signal category', 'options': dict({ }), 'original_device_class': None, @@ -1388,7 +1416,7 @@ 'original_name': 'Wi-Fi signal category', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'internal_wifi_signal_category', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'wifi_signal_category', 'unique_id': '345678-wifi_signal_category', @@ -1430,6 +1458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1437,7 +1466,7 @@ 'original_name': 'Signal strength', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'internal_wifi_signal_strength', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': None, 'unique_id': '345678-wifi_signal_strength', diff --git a/tests/components/ring/snapshots/test_siren.ambr b/tests/components/ring/snapshots/test_siren.ambr index 0c4ef24074a..b2367b28467 100644 --- a/tests/components/ring/snapshots/test_siren.ambr +++ b/tests/components/ring/snapshots/test_siren.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren', 'options': dict({ }), 'original_device_class': None, @@ -79,6 +80,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren', 'options': dict({ }), 'original_device_class': None, @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ring/snapshots/test_switch.ambr b/tests/components/ring/snapshots/test_switch.ambr index 69983644065..cd8d6c915f4 100644 --- a/tests/components/ring/snapshots/test_switch.ambr +++ b/tests/components/ring/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In-home chime', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren', 'options': dict({ }), 'original_device_class': None, @@ -174,7 +178,7 @@ 'original_name': 'Siren', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'front_siren', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'siren', 'unique_id': '765432-siren', @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection', 'options': dict({ }), 'original_device_class': None, @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren', 'options': dict({ }), 'original_device_class': None, @@ -272,7 +278,7 @@ 'original_name': 'Siren', 'platform': 'ring', 'previous_unique_id': None, - 'suggested_object_id': 'internal_siren', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'siren', 'unique_id': '345678-siren', diff --git a/tests/components/roborock/snapshots/test_binary_sensor.ambr b/tests/components/roborock/snapshots/test_binary_sensor.ambr index bcf17faa530..2213453d00c 100644 --- a/tests/components/roborock/snapshots/test_binary_sensor.ambr +++ b/tests/components/roborock/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mop attached', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water box attached', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water shortage', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mop attached', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water box attached', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water shortage', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/roborock/snapshots/test_sensor.ambr b/tests/components/roborock/snapshots/test_sensor.ambr index c0e38f83f1f..5e57187d922 100644 --- a/tests/components/roborock/snapshots/test_sensor.ambr +++ b/tests/components/roborock/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': , @@ -160,6 +162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -216,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Roller left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -292,6 +296,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -360,6 +365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -416,6 +422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -472,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -528,6 +536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mop life time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -584,6 +593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -640,6 +650,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -710,6 +721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -772,6 +784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -822,6 +835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning area', 'options': dict({ }), 'original_device_class': None, @@ -871,6 +885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -933,6 +948,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current room', 'options': dict({ }), 'original_device_class': , @@ -998,6 +1014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dock error', 'options': dict({ }), 'original_device_class': , @@ -1057,6 +1074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maintenance brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1110,6 +1128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Strainer time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1163,6 +1182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1219,6 +1239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last clean begin', 'options': dict({ }), 'original_device_class': , @@ -1268,6 +1289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last clean end', 'options': dict({ }), 'original_device_class': , @@ -1317,6 +1339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1373,6 +1396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1429,6 +1453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1531,6 +1556,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -1625,6 +1651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning area', 'options': dict({ }), 'original_device_class': None, @@ -1676,6 +1703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning count', 'options': dict({ }), 'original_device_class': None, @@ -1725,6 +1753,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1837,6 +1866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vacuum error', 'options': dict({ }), 'original_device_class': , @@ -1941,6 +1971,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1991,6 +2022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning area', 'options': dict({ }), 'original_device_class': None, @@ -2040,6 +2072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2102,6 +2135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current room', 'options': dict({ }), 'original_device_class': , @@ -2167,6 +2201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dock error', 'options': dict({ }), 'original_device_class': , @@ -2226,6 +2261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maintenance brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2279,6 +2315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Strainer time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2332,6 +2369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2388,6 +2426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last clean begin', 'options': dict({ }), 'original_device_class': , @@ -2437,6 +2476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last clean end', 'options': dict({ }), 'original_device_class': , @@ -2486,6 +2526,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2542,6 +2583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2598,6 +2640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush time left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2700,6 +2743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -2794,6 +2838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning area', 'options': dict({ }), 'original_device_class': None, @@ -2845,6 +2890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning count', 'options': dict({ }), 'original_device_class': None, @@ -2894,6 +2940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3006,6 +3053,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vacuum error', 'options': dict({ }), 'original_device_class': , @@ -3110,6 +3158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3184,6 +3233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': , @@ -3266,6 +3316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -3327,6 +3378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Washing left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/roomba/snapshots/test_sensor.ambr b/tests/components/roomba/snapshots/test_sensor.ambr index 19a1ae58d0e..60ddcdcac8a 100644 --- a/tests/components/roomba/snapshots/test_sensor.ambr +++ b/tests/components/roomba/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average mission time', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -121,6 +123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery cycles', 'options': dict({ }), 'original_device_class': None, @@ -172,6 +175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Canceled missions', 'options': dict({ }), 'original_device_class': None, @@ -222,6 +226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dock tank level', 'options': dict({ }), 'original_device_class': None, @@ -273,6 +278,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Failed missions', 'options': dict({ }), 'original_device_class': None, @@ -323,6 +329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last mission start time', 'options': dict({ }), 'original_device_class': , @@ -374,6 +381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scrubs', 'options': dict({ }), 'original_device_class': None, @@ -426,6 +434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Successful missions', 'options': dict({ }), 'original_device_class': None, @@ -476,6 +485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank level', 'options': dict({ }), 'original_device_class': None, @@ -525,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaned area', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -577,6 +588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning time', 'options': dict({ }), 'original_device_class': None, @@ -628,6 +640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total missions', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/route_b_smart_meter/snapshots/test_sensor.ambr b/tests/components/route_b_smart_meter/snapshots/test_sensor.ambr index 552e46aa687..cefd61a4972 100644 --- a/tests/components/route_b_smart_meter/snapshots/test_sensor.ambr +++ b/tests/components/route_b_smart_meter/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Instantaneous current R phase', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Instantaneous current T phase', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Instantaneous power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/rova/snapshots/test_sensor.ambr b/tests/components/rova/snapshots/test_sensor.ambr index 7d3cb7c5962..8147ce00e90 100644 --- a/tests/components/rova/snapshots/test_sensor.ambr +++ b/tests/components/rova/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bio', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Paper', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Plastic', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Residual', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/russound_rio/snapshots/test_number.ambr b/tests/components/russound_rio/snapshots/test_number.ambr index f1b806a378a..52c91f32971 100644 --- a/tests/components/russound_rio/snapshots/test_number.ambr +++ b/tests/components/russound_rio/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bass', 'options': dict({ }), 'original_device_class': None, @@ -139,6 +141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Treble', 'options': dict({ }), 'original_device_class': None, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn-on volume', 'options': dict({ }), 'original_device_class': None, @@ -253,6 +257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': None, @@ -310,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bass', 'options': dict({ }), 'original_device_class': None, @@ -367,6 +373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Treble', 'options': dict({ }), 'original_device_class': None, @@ -424,6 +431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn-on volume', 'options': dict({ }), 'original_device_class': None, @@ -481,6 +489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': None, @@ -538,6 +547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bass', 'options': dict({ }), 'original_device_class': None, @@ -595,6 +605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Treble', 'options': dict({ }), 'original_device_class': None, @@ -652,6 +663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn-on volume', 'options': dict({ }), 'original_device_class': None, @@ -709,6 +721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': None, @@ -766,6 +779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bass', 'options': dict({ }), 'original_device_class': None, @@ -823,6 +837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Treble', 'options': dict({ }), 'original_device_class': None, @@ -880,6 +895,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn-on volume', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/russound_rio/snapshots/test_switch.ambr b/tests/components/russound_rio/snapshots/test_switch.ambr index 38273b8233b..b3e48ab5b1e 100644 --- a/tests/components/russound_rio/snapshots/test_switch.ambr +++ b/tests/components/russound_rio/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Loudness', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Loudness', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Loudness', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Loudness', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/ruuvitag_ble/snapshots/test_sensor.ambr b/tests/components/ruuvitag_ble/snapshots/test_sensor.ambr index 194aa977712..27cb63b7f6b 100644 --- a/tests/components/ruuvitag_ble/snapshots/test_sensor.ambr +++ b/tests/components/ruuvitag_ble/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -181,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor air quality score', 'options': dict({ }), 'original_device_class': None, @@ -232,6 +236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index', 'options': dict({ }), 'original_device_class': None, @@ -283,6 +288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -336,6 +342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -389,6 +396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -442,6 +450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM4', 'options': dict({ }), 'original_device_class': , @@ -495,6 +504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -551,6 +561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -604,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -660,6 +672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index', 'options': dict({ }), 'original_device_class': None, @@ -711,6 +724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Acceleration total', 'options': dict({ }), 'original_device_class': None, @@ -763,6 +777,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Acceleration X', 'options': dict({ }), 'original_device_class': None, @@ -815,6 +830,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Acceleration Y', 'options': dict({ }), 'original_device_class': None, @@ -867,6 +883,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Acceleration Z', 'options': dict({ }), 'original_device_class': None, @@ -919,6 +936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -972,6 +990,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Movement counter', 'options': dict({ }), 'original_device_class': None, @@ -1023,6 +1042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1079,6 +1099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1132,6 +1153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1188,6 +1210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1244,6 +1267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -1297,6 +1321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1350,6 +1375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -1403,6 +1429,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor air quality score', 'options': dict({ }), 'original_device_class': None, @@ -1454,6 +1481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'NOx index', 'options': dict({ }), 'original_device_class': None, @@ -1505,6 +1533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -1558,6 +1587,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1614,6 +1644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1667,6 +1698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1723,6 +1755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VOC index', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sabnzbd/snapshots/test_binary_sensor.ambr b/tests/components/sabnzbd/snapshots/test_binary_sensor.ambr index 7da52a1acd7..ea9bb33b726 100644 --- a/tests/components/sabnzbd/snapshots/test_binary_sensor.ambr +++ b/tests/components/sabnzbd/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Warnings', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sabnzbd/snapshots/test_button.ambr b/tests/components/sabnzbd/snapshots/test_button.ambr index 60970ef6abd..1239046c2f7 100644 --- a/tests/components/sabnzbd/snapshots/test_button.ambr +++ b/tests/components/sabnzbd/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Resume', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sabnzbd/snapshots/test_number.ambr b/tests/components/sabnzbd/snapshots/test_number.ambr index 8fb7b0d79db..89b917cc53d 100644 --- a/tests/components/sabnzbd/snapshots/test_number.ambr +++ b/tests/components/sabnzbd/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speedlimit', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sabnzbd/snapshots/test_sensor.ambr b/tests/components/sabnzbd/snapshots/test_sensor.ambr index 3494899990c..3dbe8143dd0 100644 --- a/tests/components/sabnzbd/snapshots/test_sensor.ambr +++ b/tests/components/sabnzbd/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free disk space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left to download', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overall total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Queue', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Queue count', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -412,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -469,6 +477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -519,6 +528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total disk space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -575,6 +585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/sanix/snapshots/test_sensor.ambr b/tests/components/sanix/snapshots/test_sensor.ambr index eadd2db17b4..5c1f3aedd4b 100644 --- a/tests/components/sanix/snapshots/test_sensor.ambr +++ b/tests/components/sanix/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device number', 'options': dict({ }), 'original_device_class': None, @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -179,6 +182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filled', 'options': dict({ }), 'original_device_class': None, @@ -229,6 +233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service date', 'options': dict({ }), 'original_device_class': , @@ -278,6 +283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SSID', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/satel_integra/snapshots/test_alarm_control_panel.ambr b/tests/components/satel_integra/snapshots/test_alarm_control_panel.ambr index 33d0214976c..ed9f9efa702 100644 --- a/tests/components/satel_integra/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/satel_integra/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/satel_integra/snapshots/test_binary_sensor.ambr b/tests/components/satel_integra/snapshots/test_binary_sensor.ambr index bbb5c2a4289..f3cef5fb5b0 100644 --- a/tests/components/satel_integra/snapshots/test_binary_sensor.ambr +++ b/tests/components/satel_integra/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/satel_integra/snapshots/test_init.ambr b/tests/components/satel_integra/snapshots/test_init.ambr index 5dfa1dfb5e7..e2cac092a1f 100644 --- a/tests/components/satel_integra/snapshots/test_init.ambr +++ b/tests/components/satel_integra/snapshots/test_init.ambr @@ -71,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -106,6 +107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/satel_integra/snapshots/test_switch.ambr b/tests/components/satel_integra/snapshots/test_switch.ambr index aeb9ec90607..b716650f5bb 100644 --- a/tests/components/satel_integra/snapshots/test_switch.ambr +++ b/tests/components/satel_integra/snapshots/test_switch.ambr @@ -51,6 +51,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/saunum/conftest.py b/tests/components/saunum/conftest.py index b9808ab535d..78c6e12bbc5 100644 --- a/tests/components/saunum/conftest.py +++ b/tests/components/saunum/conftest.py @@ -2,7 +2,7 @@ from collections.abc import Generator from datetime import timedelta -from unittest.mock import MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, patch from pysaunum import SaunumData import pytest @@ -42,8 +42,8 @@ def mock_config_entry() -> MockConfigEntry: @pytest.fixture -def mock_saunum_client() -> Generator[MagicMock]: - """Return a mocked Saunum client for config flow and integration tests.""" +def mock_saunum_client_class() -> Generator[MagicMock]: + """Return a mocked Saunum client class for config flow and integration tests.""" with ( patch( "homeassistant.components.saunum.config_flow.SaunumClient", autospec=True @@ -53,6 +53,8 @@ def mock_saunum_client() -> Generator[MagicMock]: mock_client = mock_client_class.return_value mock_client.is_connected = True + mock_client_class.create = AsyncMock(return_value=mock_client) + # Create mock data for async_get_data mock_data = SaunumData( session_active=False, @@ -76,7 +78,13 @@ def mock_saunum_client() -> Generator[MagicMock]: mock_client.async_get_data.return_value = mock_data - yield mock_client + yield mock_client_class + + +@pytest.fixture +def mock_saunum_client(mock_saunum_client_class: MagicMock) -> MagicMock: + """Return a mocked Saunum client instance.""" + return mock_saunum_client_class.return_value @pytest.fixture diff --git a/tests/components/saunum/snapshots/test_binary_sensor.ambr b/tests/components/saunum/snapshots/test_binary_sensor.ambr index 561f803da94..9ae4090acb6 100644 --- a/tests/components/saunum/snapshots/test_binary_sensor.ambr +++ b/tests/components/saunum/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door open during heating alarm', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door open too long alarm', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internal temperature alarm', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature sensor disconnected alarm', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature sensor shorted alarm', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thermal cutoff alarm', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/saunum/snapshots/test_climate.ambr b/tests/components/saunum/snapshots/test_climate.ambr index 8bc774ff01d..4286c288515 100644 --- a/tests/components/saunum/snapshots/test_climate.ambr +++ b/tests/components/saunum/snapshots/test_climate.ambr @@ -17,6 +17,12 @@ ]), 'max_temp': 100, 'min_temp': 40, + 'preset_modes': list([ + 'type_1', + 'type_2', + 'type_3', + ]), + 'target_temp_step': 1.0, }), 'config_entry_id': , 'config_subentry_id': , @@ -33,6 +39,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -41,8 +48,8 @@ 'platform': 'saunum', 'previous_unique_id': None, 'suggested_object_id': None, - 'supported_features': , - 'translation_key': None, + 'supported_features': , + 'translation_key': 'saunum_climate', 'unique_id': '01K98T2T85R5GN0ZHYV25VFMMA', 'unit_of_measurement': None, }) @@ -50,7 +57,7 @@ # name: test_entities[climate.saunum_leil-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'current_temperature': 75.0, + 'current_temperature': 75, 'fan_mode': 'medium', 'fan_modes': list([ 'off', @@ -66,7 +73,14 @@ ]), 'max_temp': 100, 'min_temp': 40, - 'supported_features': , + 'preset_mode': 'type_1', + 'preset_modes': list([ + 'type_1', + 'type_2', + 'type_3', + ]), + 'supported_features': , + 'target_temp_step': 1.0, 'temperature': 80, }), 'context': , diff --git a/tests/components/saunum/snapshots/test_diagnostics.ambr b/tests/components/saunum/snapshots/test_diagnostics.ambr index 1e1fce24d29..4e3c1ccc8d6 100644 --- a/tests/components/saunum/snapshots/test_diagnostics.ambr +++ b/tests/components/saunum/snapshots/test_diagnostics.ambr @@ -33,5 +33,7 @@ 'last_update_success': True, 'update_interval': '0:01:00', }), + 'options': dict({ + }), }) # --- diff --git a/tests/components/saunum/snapshots/test_light.ambr b/tests/components/saunum/snapshots/test_light.ambr index bc4481fca03..2ab5e49b80f 100644 --- a/tests/components/saunum/snapshots/test_light.ambr +++ b/tests/components/saunum/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/saunum/snapshots/test_number.ambr b/tests/components/saunum/snapshots/test_number.ambr index 80f63e8443d..88a12dfb35c 100644 --- a/tests/components/saunum/snapshots/test_number.ambr +++ b/tests/components/saunum/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan duration', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sauna duration', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/saunum/snapshots/test_sensor.ambr b/tests/components/saunum/snapshots/test_sensor.ambr index ae5c73d07b5..687d7608956 100644 --- a/tests/components/saunum/snapshots/test_sensor.ambr +++ b/tests/components/saunum/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heater elements active', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total time turned on', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/saunum/test_climate.py b/tests/components/saunum/test_climate.py index 73b72b7923a..6a4c917070d 100644 --- a/tests/components/saunum/test_climate.py +++ b/tests/components/saunum/test_climate.py @@ -14,6 +14,7 @@ from homeassistant.components.climate import ( ATTR_FAN_MODE, ATTR_HVAC_ACTION, ATTR_HVAC_MODE, + ATTR_PRESET_MODE, DOMAIN as CLIMATE_DOMAIN, FAN_HIGH, FAN_LOW, @@ -21,10 +22,16 @@ from homeassistant.components.climate import ( FAN_OFF, SERVICE_SET_FAN_MODE, SERVICE_SET_HVAC_MODE, + SERVICE_SET_PRESET_MODE, SERVICE_SET_TEMPERATURE, HVACAction, HVACMode, ) +from homeassistant.components.saunum.const import ( + OPT_PRESET_NAME_TYPE_1, + OPT_PRESET_NAME_TYPE_2, + OPT_PRESET_NAME_TYPE_3, +) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_TEMPERATURE, @@ -88,18 +95,36 @@ async def test_climate_service_calls( expected_args: tuple, ) -> None: """Test climate service calls.""" - entity_id = "climate.saunum_leil" - await hass.services.async_call( CLIMATE_DOMAIN, service, - {ATTR_ENTITY_ID: entity_id, **service_data}, + {ATTR_ENTITY_ID: "climate.saunum_leil", **service_data}, blocking=True, ) getattr(mock_saunum_client, client_method).assert_called_once_with(*expected_args) +@pytest.mark.usefixtures("init_integration") +async def test_hvac_mode_door_open_validation( + hass: HomeAssistant, + mock_saunum_client, +) -> None: + """Test HVAC mode validation error when door is open.""" + mock_saunum_client.async_get_data.return_value.door_open = True + + with pytest.raises( + ServiceValidationError, + match="Cannot start sauna session when sauna door is open", + ): + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_HVAC_MODE, + {ATTR_ENTITY_ID: "climate.saunum_leil", ATTR_HVAC_MODE: HVACMode.HEAT}, + blocking=True, + ) + + @pytest.mark.parametrize( ("heater_elements_active", "expected_hvac_action"), [ @@ -107,29 +132,25 @@ async def test_climate_service_calls( (0, HVACAction.IDLE), ], ) -async def test_climate_hvac_actions( +async def test_hvac_actions( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_saunum_client, heater_elements_active: int, expected_hvac_action: HVACAction, ) -> None: - """Test climate HVAC actions when session is active.""" - # Get the existing mock data and modify only what we need + """Test HVAC actions when session is active.""" mock_saunum_client.async_get_data.return_value.session_active = True mock_saunum_client.async_get_data.return_value.heater_elements_active = ( heater_elements_active ) mock_config_entry.add_to_hass(hass) - assert await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() - entity_id = "climate.saunum_leil" - state = hass.states.get(entity_id) + state = hass.states.get("climate.saunum_leil") assert state is not None - assert state.state == HVACMode.HEAT assert state.attributes.get(ATTR_HVAC_ACTION) == expected_hvac_action @@ -146,7 +167,7 @@ async def test_climate_hvac_actions( (35.0, 30, 35, 30), ], ) -async def test_climate_temperature_edge_cases( +async def test_temperature_attributes( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_saunum_client, @@ -155,8 +176,7 @@ async def test_climate_temperature_edge_cases( expected_current: float | None, expected_target: int, ) -> None: - """Test climate with edge case temperature values.""" - # Get the existing mock data and modify only what we need + """Test temperature attribute handling with edge cases.""" base_data = mock_saunum_client.async_get_data.return_value mock_saunum_client.async_get_data.return_value = replace( base_data, @@ -165,14 +185,11 @@ async def test_climate_temperature_edge_cases( ) mock_config_entry.add_to_hass(hass) - assert await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() - entity_id = "climate.saunum_leil" - state = hass.states.get(entity_id) + state = hass.states.get("climate.saunum_leil") assert state is not None - assert state.attributes.get(ATTR_CURRENT_TEMPERATURE) == expected_current assert state.attributes.get(ATTR_TEMPERATURE) == expected_target @@ -205,85 +222,93 @@ async def test_entity_unavailable_on_update_failure( assert state.state == STATE_UNAVAILABLE -@pytest.mark.usefixtures("init_integration") -async def test_hvac_mode_error_handling( - hass: HomeAssistant, - mock_saunum_client, -) -> None: - """Test error handling when setting HVAC mode fails.""" - entity_id = "climate.saunum_leil" - - # Make the client method raise an exception - mock_saunum_client.async_start_session.side_effect = SaunumException( - "Communication error" - ) - - # Try to call the service and expect HomeAssistantError - with pytest.raises(HomeAssistantError) as exc_info: - await hass.services.async_call( - CLIMATE_DOMAIN, +@pytest.mark.parametrize( + ("service", "service_data", "mock_method", "side_effect", "translation_key"), + [ + ( SERVICE_SET_HVAC_MODE, - {ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.HEAT}, - blocking=True, - ) - - # Verify the exception has the correct translation key - assert exc_info.value.translation_key == "set_hvac_mode_failed" - assert exc_info.value.translation_domain == "saunum" - - -@pytest.mark.usefixtures("init_integration") -async def test_hvac_mode_door_open_validation( - hass: HomeAssistant, - mock_saunum_client, -) -> None: - """Test validation error when trying to heat with door open.""" - entity_id = "climate.saunum_leil" - - # Set door to open - mock_saunum_client.async_get_data.return_value.door_open = True - - # Try to turn on heating with door open - with pytest.raises(ServiceValidationError) as exc_info: - await hass.services.async_call( - CLIMATE_DOMAIN, - SERVICE_SET_HVAC_MODE, - {ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.HEAT}, - blocking=True, - ) - - # Verify the exception has the correct translation key - assert exc_info.value.translation_key == "door_open" - assert exc_info.value.translation_domain == "saunum" - - -@pytest.mark.usefixtures("init_integration") -async def test_temperature_error_handling( - hass: HomeAssistant, - mock_saunum_client, -) -> None: - """Test error handling when setting temperature fails.""" - entity_id = "climate.saunum_leil" - - # Make the client method raise an exception - mock_saunum_client.async_set_target_temperature.side_effect = SaunumException( - "Communication error" - ) - - # Try to call the service and expect HomeAssistantError - with pytest.raises(HomeAssistantError) as exc_info: - await hass.services.async_call( - CLIMATE_DOMAIN, + {ATTR_HVAC_MODE: HVACMode.HEAT}, + "async_start_session", + SaunumException("Communication error"), + "set_hvac_mode_failed", + ), + ( SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 85}, + {ATTR_TEMPERATURE: 85}, + "async_set_target_temperature", + SaunumException("Communication error"), + "set_temperature_failed", + ), + ( + SERVICE_SET_PRESET_MODE, + {ATTR_PRESET_MODE: "type_2"}, + "async_set_sauna_type", + SaunumException("Communication error"), + "set_preset_failed", + ), + ], +) +@pytest.mark.usefixtures("init_integration") +async def test_service_error_handling( + hass: HomeAssistant, + mock_saunum_client, + service: str, + service_data: dict, + mock_method: str, + side_effect: Exception, + translation_key: str, +) -> None: + """Test error handling when service calls fail.""" + entity_id = "climate.saunum_leil" + + getattr(mock_saunum_client, mock_method).side_effect = side_effect + + with pytest.raises(HomeAssistantError) as exc_info: + await hass.services.async_call( + CLIMATE_DOMAIN, + service, + {ATTR_ENTITY_ID: entity_id, **service_data}, blocking=True, ) - # Verify the exception has the correct translation key - assert exc_info.value.translation_key == "set_temperature_failed" + assert exc_info.value.translation_key == translation_key assert exc_info.value.translation_domain == "saunum" +@pytest.mark.usefixtures("init_integration") +async def test_fan_mode_service_call( + hass: HomeAssistant, + mock_saunum_client, +) -> None: + """Test setting fan mode.""" + mock_saunum_client.async_get_data.return_value.session_active = True + + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_FAN_MODE, + {ATTR_ENTITY_ID: "climate.saunum_leil", ATTR_FAN_MODE: FAN_LOW}, + blocking=True, + ) + + mock_saunum_client.async_set_fan_speed.assert_called_once_with(1) + + +@pytest.mark.usefixtures("init_integration") +async def test_preset_mode_service_call( + hass: HomeAssistant, + mock_saunum_client, +) -> None: + """Test setting preset mode.""" + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_PRESET_MODE, + {ATTR_ENTITY_ID: "climate.saunum_leil", ATTR_PRESET_MODE: "type_2"}, + blocking=True, + ) + + mock_saunum_client.async_set_sauna_type.assert_called_once_with(1) + + @pytest.mark.parametrize( ("fan_speed", "fan_mode"), [ @@ -294,79 +319,157 @@ async def test_temperature_error_handling( (None, None), ], ) -async def test_fan_mode_read( +async def test_fan_mode_attributes( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_saunum_client, fan_speed: int | None, fan_mode: str | None, ) -> None: - """Test fan mode states mapping from device.""" - # Set up initial state with the fan_speed and active session + """Test fan mode attribute mapping from device.""" mock_saunum_client.async_get_data.return_value.fan_speed = fan_speed mock_saunum_client.async_get_data.return_value.session_active = True mock_config_entry.add_to_hass(hass) - assert await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() - entity_id = "climate.saunum_leil" - - # Test reading fan mode - state = hass.states.get(entity_id) + state = hass.states.get("climate.saunum_leil") assert state is not None assert state.attributes.get(ATTR_FAN_MODE) == fan_mode -@pytest.mark.parametrize( - ("fan_speed", "fan_mode"), - [ - (0, FAN_OFF), - (1, FAN_LOW), - (2, FAN_MEDIUM), - (3, FAN_HIGH), - ], -) -async def test_fan_mode_write( - hass: HomeAssistant, - mock_config_entry: MockConfigEntry, - mock_saunum_client, - fan_speed: int, - fan_mode: str, -) -> None: - """Test setting fan mode.""" - # Ensure session is active so fan mode can be changed - mock_saunum_client.async_get_data.return_value.session_active = True - - mock_config_entry.add_to_hass(hass) - - assert await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() - - entity_id = "climate.saunum_leil" - - await hass.services.async_call( - CLIMATE_DOMAIN, - SERVICE_SET_FAN_MODE, - {ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: fan_mode}, - blocking=True, - ) - - mock_saunum_client.async_set_fan_speed.assert_called_once_with(fan_speed) - - @pytest.mark.usefixtures("init_integration") -async def test_fan_mode_session_not_active_error( +async def test_fan_mode_validation_error( hass: HomeAssistant, mock_saunum_client, ) -> None: """Test fan mode validation error when session is not active.""" - # Set session state to inactive mock_saunum_client.async_get_data.return_value.session_active = False + with pytest.raises( + ServiceValidationError, + match="Cannot change fan mode when sauna session is not active", + ): + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_FAN_MODE, + {ATTR_ENTITY_ID: "climate.saunum_leil", ATTR_FAN_MODE: FAN_LOW}, + blocking=True, + ) + + +@pytest.mark.usefixtures("init_integration") +async def test_preset_mode_validation_error( + hass: HomeAssistant, + mock_saunum_client, +) -> None: + """Test preset mode validation error when session is active.""" + mock_saunum_client.async_get_data.return_value.session_active = True + + with pytest.raises(ServiceValidationError) as exc_info: + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_PRESET_MODE, + {ATTR_ENTITY_ID: "climate.saunum_leil", ATTR_PRESET_MODE: "type_2"}, + blocking=True, + ) + + assert exc_info.value.translation_key == "preset_session_active" + assert exc_info.value.translation_domain == "saunum" + + +@pytest.mark.parametrize( + ("sauna_type", "expected_preset"), + [ + (0, "type_1"), + (1, "type_2"), + (2, "type_3"), + (None, "type_1"), + ], +) +async def test_preset_mode_attributes_default_names( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_saunum_client, + sauna_type: int | None, + expected_preset: str, +) -> None: + """Test preset mode attributes with default names.""" + mock_saunum_client.async_get_data.return_value.sauna_type = sauna_type + + mock_config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get("climate.saunum_leil") + assert state is not None + assert state.attributes.get(ATTR_PRESET_MODE) == expected_preset + + +async def test_preset_mode_attributes_custom_names( + hass: HomeAssistant, + mock_saunum_client, +) -> None: + """Test preset mode attributes with custom names.""" + custom_options = { + OPT_PRESET_NAME_TYPE_1: "Finnish Sauna", + OPT_PRESET_NAME_TYPE_2: "Turkish Bath", + OPT_PRESET_NAME_TYPE_3: "Steam Room", + } + mock_config_entry = MockConfigEntry( + domain="saunum", + data={"host": "192.168.1.100"}, + options=custom_options, + title="Saunum", + ) + mock_saunum_client.async_get_data.return_value.sauna_type = 1 + + mock_config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get("climate.saunum_leil") + assert state is not None + assert state.attributes.get(ATTR_PRESET_MODE) == "Turkish Bath" + + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_PRESET_MODE, + {ATTR_ENTITY_ID: "climate.saunum_leil", ATTR_PRESET_MODE: "Steam Room"}, + blocking=True, + ) + mock_saunum_client.async_set_sauna_type.assert_called_once_with(2) + + +async def test_preset_mode_options_update( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_saunum_client, +) -> None: + """Test that preset names update when options are changed.""" entity_id = "climate.saunum_leil" + mock_config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get("climate.saunum_leil") + assert state is not None + assert "type_1" in state.attributes.get("preset_modes", []) + + custom_options = { + OPT_PRESET_NAME_TYPE_1: "Custom Type 1", + OPT_PRESET_NAME_TYPE_2: "Custom Type 2", + OPT_PRESET_NAME_TYPE_3: "Custom Type 3", + } + hass.config_entries.async_update_entry(mock_config_entry, options=custom_options) + await hass.async_block_till_done() + + state = hass.states.get("climate.saunum_leil") + assert state is not None + assert "Custom Type 1" in state.attributes.get("preset_modes", []) + assert "type_1" not in state.attributes.get("preset_modes", []) # Try to set fan mode and expect error with pytest.raises( ServiceValidationError, @@ -378,3 +481,33 @@ async def test_fan_mode_session_not_active_error( {ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_LOW}, blocking=True, ) + + +@pytest.mark.usefixtures("init_integration") +async def test_fan_mode_error_handling( + hass: HomeAssistant, + mock_saunum_client, +) -> None: + """Test error handling when setting fan mode fails.""" + entity_id = "climate.saunum_leil" + + # Ensure session is active + mock_saunum_client.async_get_data.return_value.session_active = True + + # Make the client method raise an exception + mock_saunum_client.async_set_fan_speed.side_effect = SaunumException( + "Communication error" + ) + + # Try to call the service and expect HomeAssistantError + with pytest.raises(HomeAssistantError) as exc_info: + await hass.services.async_call( + CLIMATE_DOMAIN, + SERVICE_SET_FAN_MODE, + {ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_LOW}, + blocking=True, + ) + + # Verify the exception has the correct translation key + assert exc_info.value.translation_key == "set_fan_mode_failed" + assert exc_info.value.translation_domain == "saunum" diff --git a/tests/components/saunum/test_config_flow.py b/tests/components/saunum/test_config_flow.py index 88ca5e4909c..7f720f445c3 100644 --- a/tests/components/saunum/test_config_flow.py +++ b/tests/components/saunum/test_config_flow.py @@ -7,7 +7,12 @@ from unittest.mock import AsyncMock from pysaunum import SaunumConnectionError, SaunumException import pytest -from homeassistant.components.saunum.const import DOMAIN +from homeassistant.components.saunum.const import ( + DOMAIN, + OPT_PRESET_NAME_TYPE_1, + OPT_PRESET_NAME_TYPE_2, + OPT_PRESET_NAME_TYPE_3, +) from homeassistant.config_entries import SOURCE_USER from homeassistant.const import CONF_HOST from homeassistant.core import HomeAssistant @@ -49,14 +54,13 @@ async def test_full_flow(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> No ) async def test_form_errors( hass: HomeAssistant, - mock_saunum_client, + mock_saunum_client_class, side_effect: Exception, error_base: str, mock_setup_entry: AsyncMock, ) -> None: """Test error handling and recovery.""" - mock_saunum_client.connect.side_effect = side_effect - + mock_saunum_client_class.create.side_effect = side_effect result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} ) @@ -69,8 +73,8 @@ async def test_form_errors( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": error_base} - # Test recovery - clear the error and try again - mock_saunum_client.connect.side_effect = None + # Test recovery - try again without the error + mock_saunum_client_class.create.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -139,20 +143,20 @@ async def test_reconfigure_flow( async def test_reconfigure_errors( hass: HomeAssistant, mock_config_entry: MockConfigEntry, - mock_saunum_client, + mock_saunum_client_class, side_effect: Exception, error_base: str, mock_setup_entry: AsyncMock, ) -> None: """Test reconfigure flow error handling.""" mock_config_entry.add_to_hass(hass) - mock_saunum_client.connect.side_effect = side_effect result = await mock_config_entry.start_reconfigure_flow(hass) assert result["type"] is FlowResultType.FORM assert result["step_id"] == "user" + mock_saunum_client_class.create.side_effect = side_effect result = await hass.config_entries.flow.async_configure( result["flow_id"], TEST_RECONFIGURE_INPUT, @@ -161,8 +165,8 @@ async def test_reconfigure_errors( assert result["type"] is FlowResultType.FORM assert result["errors"] == {"base": error_base} - # Test recovery - clear the error and try again - mock_saunum_client.connect.side_effect = None + # Test recovery - try again without the error + mock_saunum_client_class.create.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -202,3 +206,82 @@ async def test_reconfigure_to_existing_host( # Verify the original entry was not changed assert mock_config_entry.data == TEST_USER_INPUT + + +@pytest.mark.usefixtures("mock_saunum_client") +async def test_options_flow( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_setup_entry: AsyncMock, +) -> None: + """Test options flow for configuring preset names.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" + + # Configure custom preset names + custom_options = { + OPT_PRESET_NAME_TYPE_1: "Finnish Sauna", + OPT_PRESET_NAME_TYPE_2: "Turkish Bath", + OPT_PRESET_NAME_TYPE_3: "Steam Room", + } + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input=custom_options, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == custom_options + assert mock_config_entry.options == custom_options + + +@pytest.mark.usefixtures("mock_saunum_client") +async def test_options_flow_with_existing_options( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_setup_entry: AsyncMock, +) -> None: + """Test options flow with existing custom preset names.""" + existing_options = { + OPT_PRESET_NAME_TYPE_1: "My Custom Type 1", + OPT_PRESET_NAME_TYPE_2: "My Custom Type 2", + OPT_PRESET_NAME_TYPE_3: "My Custom Type 3", + } + + # Set up entry with existing options + mock_config_entry = MockConfigEntry( + domain=DOMAIN, + data=TEST_USER_INPUT, + options=existing_options, + title="Saunum", + ) + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + result = await hass.config_entries.options.async_init(mock_config_entry.entry_id) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "init" + + # Update one option + updated_options = { + OPT_PRESET_NAME_TYPE_1: "Updated Type 1", + OPT_PRESET_NAME_TYPE_2: "My Custom Type 2", + OPT_PRESET_NAME_TYPE_3: "My Custom Type 3", + } + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input=updated_options, + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["data"] == updated_options + assert mock_config_entry.options == updated_options diff --git a/tests/components/saunum/test_init.py b/tests/components/saunum/test_init.py index 13efaf70cda..3a41acf57b5 100644 --- a/tests/components/saunum/test_init.py +++ b/tests/components/saunum/test_init.py @@ -1,5 +1,7 @@ """Test Saunum Leil integration setup and teardown.""" +from unittest.mock import patch + from pysaunum import SaunumConnectionError import pytest from syrupy.assertion import SnapshotAssertion @@ -35,9 +37,11 @@ async def test_async_setup_entry_connection_failed( """Test integration setup fails when connection cannot be established.""" mock_config_entry.add_to_hass(hass) - mock_saunum_client.connect.side_effect = SaunumConnectionError("Connection failed") - - assert not await hass.config_entries.async_setup(mock_config_entry.entry_id) + with patch( + "homeassistant.components.saunum.SaunumClient.create", + side_effect=SaunumConnectionError("Connection failed"), + ): + assert not await hass.config_entries.async_setup(mock_config_entry.entry_id) assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY diff --git a/tests/components/saunum/test_number.py b/tests/components/saunum/test_number.py index dea753e0f40..80b5dcd68fa 100644 --- a/tests/components/saunum/test_number.py +++ b/tests/components/saunum/test_number.py @@ -136,7 +136,7 @@ async def test_set_value_while_session_active( # Attempt to set value should raise ServiceValidationError with pytest.raises( ServiceValidationError, - match="Cannot change sauna duration while session is active", + match="Cannot change sauna duration while sauna session is active", ): await hass.services.async_call( NUMBER_DOMAIN, diff --git a/tests/components/saunum/test_sensor.py b/tests/components/saunum/test_sensor.py index 9fa223ecaa0..dc28812e87c 100644 --- a/tests/components/saunum/test_sensor.py +++ b/tests/components/saunum/test_sensor.py @@ -52,7 +52,7 @@ async def test_sensor_not_created_when_value_is_none( assert await hass.config_entries.async_setup(mock_config_entry.entry_id) await hass.async_block_till_done() - assert hass.states.get("sensor.saunum_leil_temperature") is None + assert hass.states.get("sensor.saunum_leil_current_temperature") is None assert hass.states.get("sensor.saunum_leil_heater_elements_active") is None assert hass.states.get("sensor.saunum_leil_on_time") is None diff --git a/tests/components/scene/test_trigger.py b/tests/components/scene/test_trigger.py index 1361e211a5f..7549056f655 100644 --- a/tests/components/scene/test_trigger.py +++ b/tests/components/scene/test_trigger.py @@ -1,8 +1,5 @@ """Test scene trigger.""" -from collections.abc import Generator -from unittest.mock import patch - import pytest from homeassistant.const import ( @@ -14,7 +11,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, set_or_remove_state, @@ -22,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_scenes(hass: HomeAssistant) -> list[str]: """Create multiple scene entities associated with different targets.""" @@ -57,7 +39,7 @@ async def test_scene_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("scene"), @@ -163,7 +145,7 @@ async def test_scene_state_trigger_behavior_any( entity_id: str, entities_in_target: int, trigger: str, - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the scene state trigger fires when any scene state changes to a specific state.""" other_entity_ids = set(target_scenes) - {entity_id} diff --git a/tests/components/script/conftest.py b/tests/components/script/conftest.py deleted file mode 100644 index 8795ba3c018..00000000000 --- a/tests/components/script/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Conftest for script tests.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/search/test_init.py b/tests/components/search/test_init.py index 2c00c3bf6f2..268f829ba0a 100644 --- a/tests/components/search/test_init.py +++ b/tests/components/search/test_init.py @@ -1,6 +1,5 @@ """Tests for Search integration.""" -import pytest from pytest_unordered import unordered from homeassistant.components.search import ItemType, Searcher @@ -19,11 +18,6 @@ from tests.common import MockConfigEntry from tests.typing import WebSocketGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_search( hass: HomeAssistant, area_registry: ar.AreaRegistry, diff --git a/tests/components/sense/snapshots/test_binary_sensor.ambr b/tests/components/sense/snapshots/test_binary_sensor.ambr index aa803b40bd1..ad4b8853c98 100644 --- a/tests/components/sense/snapshots/test_binary_sensor.ambr +++ b/tests/components/sense/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sense/snapshots/test_sensor.ambr b/tests/components/sense/snapshots/test_sensor.ambr index d1b0c90aa23..af6fc43351e 100644 --- a/tests/components/sense/snapshots/test_sensor.ambr +++ b/tests/components/sense/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -138,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -254,6 +258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -312,6 +317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -370,6 +376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -428,6 +435,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -486,6 +494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -544,6 +553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -602,6 +612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -660,6 +671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -718,6 +730,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -776,6 +789,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill From Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -834,6 +848,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill Net Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -890,6 +905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill Net Production Percentage', 'options': dict({ }), 'original_device_class': None, @@ -942,6 +958,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -998,6 +1015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill Solar Powered Percentage', 'options': dict({ }), 'original_device_class': None, @@ -1050,6 +1068,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bill To Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1108,6 +1127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1166,6 +1186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily From Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1224,6 +1245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily Net Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1280,6 +1302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily Net Production Percentage', 'options': dict({ }), 'original_device_class': None, @@ -1332,6 +1355,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1388,6 +1412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily Solar Powered Percentage', 'options': dict({ }), 'original_device_class': None, @@ -1440,6 +1465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily To Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1498,6 +1524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1555,6 +1582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'L1 Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1612,6 +1640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'L2 Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1669,6 +1698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1727,6 +1757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly From Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1785,6 +1816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly Net Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1841,6 +1873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly Net Production Percentage', 'options': dict({ }), 'original_device_class': None, @@ -1893,6 +1926,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1949,6 +1983,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly Solar Powered Percentage', 'options': dict({ }), 'original_device_class': None, @@ -2001,6 +2036,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly To Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2059,6 +2095,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2116,6 +2153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2174,6 +2212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly From Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2232,6 +2271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly Net Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2288,6 +2328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly Net Production Percentage', 'options': dict({ }), 'original_device_class': None, @@ -2340,6 +2381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2396,6 +2438,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly Solar Powered Percentage', 'options': dict({ }), 'original_device_class': None, @@ -2448,6 +2491,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weekly To Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2506,6 +2550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2564,6 +2609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly From Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2622,6 +2668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly Net Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2678,6 +2725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly Net Production Percentage', 'options': dict({ }), 'original_device_class': None, @@ -2730,6 +2778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly Production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2786,6 +2835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly Solar Powered Percentage', 'options': dict({ }), 'original_device_class': None, @@ -2838,6 +2888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly To Grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/sensibo/snapshots/test_binary_sensor.ambr b/tests/components/sensibo/snapshots/test_binary_sensor.ambr index fb12dce55ac..1e78257daf1 100644 --- a/tests/components/sensibo/snapshots/test_binary_sensor.ambr +++ b/tests/components/sensibo/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter clean required', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with AC', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with indoor air quality', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with outdoor air quality', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with presence', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter clean required', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main sensor', 'options': dict({ }), 'original_device_class': None, @@ -411,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -460,6 +469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room occupied', 'options': dict({ }), 'original_device_class': , @@ -509,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter clean required', 'options': dict({ }), 'original_device_class': , @@ -558,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with AC', 'options': dict({ }), 'original_device_class': , @@ -607,6 +619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with indoor air quality', 'options': dict({ }), 'original_device_class': , @@ -656,6 +669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with outdoor air quality', 'options': dict({ }), 'original_device_class': , @@ -705,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost linked with presence', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sensibo/snapshots/test_button.ambr b/tests/components/sensibo/snapshots/test_button.ambr index 3632560b861..b3e9487dcba 100644 --- a/tests/components/sensibo/snapshots/test_button.ambr +++ b/tests/components/sensibo/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sensibo/snapshots/test_climate.ambr b/tests/components/sensibo/snapshots/test_climate.ambr index fc6e6f64be8..7c3ca00b8ee 100644 --- a/tests/components/sensibo/snapshots/test_climate.ambr +++ b/tests/components/sensibo/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -110,6 +111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -203,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sensibo/snapshots/test_number.ambr b/tests/components/sensibo/snapshots/test_number.ambr index e1556b3cdf8..82266af1b63 100644 --- a/tests/components/sensibo/snapshots/test_number.ambr +++ b/tests/components/sensibo/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity calibration', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature calibration', 'options': dict({ }), 'original_device_class': , @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity calibration', 'options': dict({ }), 'original_device_class': , @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature calibration', 'options': dict({ }), 'original_device_class': , @@ -261,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity calibration', 'options': dict({ }), 'original_device_class': , @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature calibration', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sensibo/snapshots/test_select.ambr b/tests/components/sensibo/snapshots/test_select.ambr index 2ac6eb445a5..77c60ebe5f4 100644 --- a/tests/components/sensibo/snapshots/test_select.ambr +++ b/tests/components/sensibo/snapshots/test_select.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sensibo/snapshots/test_sensor.ambr b/tests/components/sensibo/snapshots/test_sensor.ambr index 98552394ccc..16577934026 100644 --- a/tests/components/sensibo/snapshots/test_sensor.ambr +++ b/tests/components/sensibo/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter last reset', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure AQI', 'options': dict({ }), 'original_device_class': , @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -179,6 +182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate React high temperature threshold', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -243,6 +247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate React low temperature threshold', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -305,6 +310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate React type', 'options': dict({ }), 'original_device_class': None, @@ -353,6 +359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter last reset', 'options': dict({ }), 'original_device_class': , @@ -404,6 +411,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -460,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -513,6 +522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RSSI', 'options': dict({ }), 'original_device_class': , @@ -566,6 +576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -622,6 +633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -676,6 +688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Timer end time', 'options': dict({ }), 'original_device_class': , @@ -727,6 +740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter last reset', 'options': dict({ }), 'original_device_class': , @@ -782,6 +796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure AQI', 'options': dict({ }), 'original_device_class': , @@ -836,6 +851,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure sensitivity', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sensibo/snapshots/test_switch.ambr b/tests/components/sensibo/snapshots/test_switch.ambr index f52f650ee7d..14032f99a98 100644 --- a/tests/components/sensibo/snapshots/test_switch.ambr +++ b/tests/components/sensibo/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate React', 'options': dict({ }), 'original_device_class': , @@ -119,6 +121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Timer', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pure Boost', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sensibo/snapshots/test_update.ambr b/tests/components/sensibo/snapshots/test_update.ambr index b5e4b159264..0aea04fd0ec 100644 --- a/tests/components/sensibo/snapshots/test_update.ambr +++ b/tests/components/sensibo/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sensor/test_device_condition.py b/tests/components/sensor/test_device_condition.py index e33dd0ffb52..67f07e3293a 100644 --- a/tests/components/sensor/test_device_condition.py +++ b/tests/components/sensor/test_device_condition.py @@ -31,11 +31,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( "device_class", [ diff --git a/tests/components/sensor/test_device_trigger.py b/tests/components/sensor/test_device_trigger.py index 43476a6a43b..8b407ac5576 100644 --- a/tests/components/sensor/test_device_trigger.py +++ b/tests/components/sensor/test_device_trigger.py @@ -35,11 +35,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.mark.parametrize( "device_class", [ diff --git a/tests/components/sensor/test_init.py b/tests/components/sensor/test_init.py index 8123cbc5f16..b25eaa0a4d0 100644 --- a/tests/components/sensor/test_init.py +++ b/tests/components/sensor/test_init.py @@ -3107,10 +3107,8 @@ def test_device_class_converters_are_complete() -> None: SensorDeviceClass.IRRADIANCE, SensorDeviceClass.MOISTURE, SensorDeviceClass.MONETARY, - SensorDeviceClass.NITROGEN_DIOXIDE, SensorDeviceClass.NITROGEN_MONOXIDE, SensorDeviceClass.NITROUS_OXIDE, - SensorDeviceClass.OZONE, SensorDeviceClass.PH, SensorDeviceClass.PM1, SensorDeviceClass.PM10, @@ -3118,7 +3116,6 @@ def test_device_class_converters_are_complete() -> None: SensorDeviceClass.PM4, SensorDeviceClass.SIGNAL_STRENGTH, SensorDeviceClass.SOUND_PRESSURE, - SensorDeviceClass.SULPHUR_DIOXIDE, SensorDeviceClass.TIMESTAMP, SensorDeviceClass.WIND_DIRECTION, } diff --git a/tests/components/sensorpush_cloud/snapshots/test_sensor.ambr b/tests/components/sensorpush_cloud/snapshots/test_sensor.ambr index 7992b82a4d3..e182b3c8abd 100644 --- a/tests/components/sensorpush_cloud/snapshots/test_sensor.ambr +++ b/tests/components/sensorpush_cloud/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Altitude', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -252,6 +256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -305,6 +310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vapor pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Altitude', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -529,6 +538,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -588,6 +598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -644,6 +655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -700,6 +712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -753,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -806,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -862,6 +877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vapor pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -918,6 +934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Altitude', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -977,6 +994,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1036,6 +1054,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1092,6 +1111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1148,6 +1168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1201,6 +1222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1254,6 +1276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1310,6 +1333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vapor pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/senz/snapshots/test_climate.ambr b/tests/components/senz/snapshots/test_climate.ambr index ad217da1bfa..3ad92f06190 100644 --- a/tests/components/senz/snapshots/test_climate.ambr +++ b/tests/components/senz/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -92,6 +93,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/senz/snapshots/test_sensor.ambr b/tests/components/senz/snapshots/test_sensor.ambr index 8e35f51573c..051ad2d9fe2 100644 --- a/tests/components/senz/snapshots/test_sensor.ambr +++ b/tests/components/senz/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/sfr_box/snapshots/test_binary_sensor.ambr b/tests/components/sfr_box/snapshots/test_binary_sensor.ambr index 524c4eb8d61..78f021d283f 100644 --- a/tests/components/sfr_box/snapshots/test_binary_sensor.ambr +++ b/tests/components/sfr_box/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'WAN status', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FTTH status', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'WAN status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sfr_box/snapshots/test_button.ambr b/tests/components/sfr_box/snapshots/test_button.ambr index 8598b3b21ab..f4bf46f66bb 100644 --- a/tests/components/sfr_box/snapshots/test_button.ambr +++ b/tests/components/sfr_box/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sfr_box/snapshots/test_sensor.ambr b/tests/components/sfr_box/snapshots/test_sensor.ambr index b524d7cf5e9..9c4fa209cda 100644 --- a/tests/components/sfr_box/snapshots/test_sensor.ambr +++ b/tests/components/sfr_box/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL attenuation down', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL attenuation up', 'options': dict({ }), 'original_device_class': , @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL connect count', 'options': dict({ }), 'original_device_class': None, @@ -175,6 +178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL CRC error count', 'options': dict({ }), 'original_device_class': None, @@ -224,6 +228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL line mode', 'options': dict({ }), 'original_device_class': None, @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL line status', 'options': dict({ }), 'original_device_class': , @@ -338,6 +344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL noise down', 'options': dict({ }), 'original_device_class': , @@ -391,6 +398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL noise up', 'options': dict({ }), 'original_device_class': , @@ -444,6 +452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL rate down', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -500,6 +509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL rate up', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -566,6 +576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DSL training', 'options': dict({ }), 'original_device_class': , @@ -632,6 +643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Network infrastructure', 'options': dict({ }), 'original_device_class': , @@ -688,6 +700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -744,6 +757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -805,6 +819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'WAN mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/shelly/snapshots/test_binary_sensor.ambr b/tests/components/shelly/snapshots/test_binary_sensor.ambr index 9caad9e3516..3abe0350642 100644 --- a/tests/components/shelly/snapshots/test_binary_sensor.ambr +++ b/tests/components/shelly/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibration', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen cable unplugged', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen flood', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen mute', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/shelly/snapshots/test_button.ambr b/tests/components/shelly/snapshots/test_button.ambr index 6557e052d90..728e7cc6ada 100644 --- a/tests/components/shelly/snapshots/test_button.ambr +++ b/tests/components/shelly/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibrate', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button', 'options': dict({ }), 'original_device_class': None, @@ -165,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn off the screen', 'options': dict({ }), 'original_device_class': None, @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn on the screen', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/shelly/snapshots/test_climate.ambr b/tests/components/shelly/snapshots/test_climate.ambr index ebc03966a0b..48c44f98708 100644 --- a/tests/components/shelly/snapshots/test_climate.ambr +++ b/tests/components/shelly/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -98,6 +99,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -171,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -243,6 +246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -330,6 +334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -415,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/shelly/snapshots/test_devices.ambr b/tests/components/shelly/snapshots/test_devices.ambr index ae79c11bf67..142d325d709 100644 --- a/tests/components/shelly/snapshots/test_devices.ambr +++ b/tests/components/shelly/snapshots/test_devices.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -172,6 +175,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot intensity', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot intensity', 'options': dict({ }), 'original_device_class': None, @@ -293,6 +298,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -350,6 +356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -401,6 +408,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot level', 'options': dict({ }), 'original_device_class': None, @@ -451,6 +459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot vial', 'options': dict({ }), 'original_device_class': None, @@ -501,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot level', 'options': dict({ }), 'original_device_class': None, @@ -551,6 +561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot vial', 'options': dict({ }), 'original_device_class': None, @@ -601,6 +612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -652,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away mode', 'options': dict({ }), 'original_device_class': None, @@ -700,6 +713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot', 'options': dict({ }), 'original_device_class': None, @@ -748,6 +762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot boost', 'options': dict({ }), 'original_device_class': None, @@ -796,6 +811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot', 'options': dict({ }), 'original_device_class': None, @@ -844,6 +860,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot boost', 'options': dict({ }), 'original_device_class': None, @@ -892,6 +909,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -953,6 +971,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1014,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -1063,6 +1083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -1112,6 +1133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -1169,6 +1191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Living room lamp', 'options': dict({ }), 'original_device_class': None, @@ -1232,6 +1255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -1283,6 +1307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Living room lamp energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1342,6 +1367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Living room lamp power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1398,6 +1424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1449,6 +1476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -1510,6 +1538,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1571,6 +1600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -1620,6 +1650,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -1669,6 +1700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -1718,6 +1750,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -1767,6 +1800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -1816,6 +1850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -1865,6 +1900,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -1914,6 +1950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -1963,6 +2000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -2012,6 +2050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -2061,6 +2100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -2110,6 +2150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -2159,6 +2200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -2208,6 +2250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -2257,6 +2300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -2306,6 +2350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -2355,6 +2400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -2404,6 +2450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -2453,6 +2500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -2506,6 +2554,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2561,6 +2610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2617,6 +2667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2676,6 +2727,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2735,6 +2787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2794,6 +2847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2850,6 +2904,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2906,6 +2961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2962,6 +3018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3018,6 +3075,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3077,6 +3135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3136,6 +3195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3195,6 +3255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3251,6 +3312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3307,6 +3369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3361,6 +3424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -3412,6 +3476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3468,6 +3533,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3527,6 +3593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3586,6 +3653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3645,6 +3713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3701,6 +3770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3757,6 +3827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3813,6 +3884,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3869,6 +3941,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3928,6 +4001,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3987,6 +4061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4046,6 +4121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4102,6 +4178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4158,6 +4235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4214,6 +4292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -4265,6 +4344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -4313,6 +4393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -4361,6 +4442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -4409,6 +4491,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -4470,6 +4553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -4531,6 +4615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -4580,6 +4665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'My zone occupancy', 'options': dict({ }), 'original_device_class': , @@ -4629,6 +4715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'New zone occupancy', 'options': dict({ }), 'original_device_class': , @@ -4678,6 +4765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -4727,6 +4815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room occupancy', 'options': dict({ }), 'original_device_class': , @@ -4776,6 +4865,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -4831,6 +4921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance level', 'options': dict({ }), 'original_device_class': , @@ -4885,6 +4976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -4936,6 +5028,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'My zone detected objects', 'options': dict({ }), 'original_device_class': None, @@ -4988,6 +5081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'New zone detected objects', 'options': dict({ }), 'original_device_class': None, @@ -5040,6 +5134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room detected objects', 'options': dict({ }), 'original_device_class': None, @@ -5092,6 +5187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -5143,6 +5239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -5204,6 +5301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -5265,6 +5363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -5314,6 +5413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External power', 'options': dict({ }), 'original_device_class': , @@ -5363,6 +5463,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2', 'options': dict({ }), 'original_device_class': , @@ -5412,6 +5513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -5461,6 +5563,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -5510,6 +5613,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn off the screen', 'options': dict({ }), 'original_device_class': None, @@ -5558,6 +5662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn on the screen', 'options': dict({ }), 'original_device_class': None, @@ -5607,6 +5712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 0', 'options': dict({ }), 'original_device_class': , @@ -5666,6 +5772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3', 'options': dict({ }), 'original_device_class': , @@ -5725,6 +5832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4', 'options': dict({ }), 'original_device_class': , @@ -5785,6 +5893,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5841,6 +5950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -5898,6 +6008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance level', 'options': dict({ }), 'original_device_class': , @@ -5952,6 +6063,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -6003,6 +6115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -6056,6 +6169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6110,6 +6224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -6158,6 +6273,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -6219,6 +6335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -6280,6 +6397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -6329,6 +6447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 0', 'options': dict({ }), 'original_device_class': , @@ -6378,6 +6497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1', 'options': dict({ }), 'original_device_class': , @@ -6427,6 +6547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -6476,6 +6597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -6525,6 +6647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -6574,6 +6697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -6623,6 +6747,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -6672,6 +6797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -6721,6 +6847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -6773,6 +6900,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6829,6 +6957,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6888,6 +7017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6942,6 +7072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -6993,6 +7124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7049,6 +7181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -7102,6 +7235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7158,6 +7292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7212,6 +7347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -7273,6 +7409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -7334,6 +7471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -7383,6 +7521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 0', 'options': dict({ }), 'original_device_class': , @@ -7432,6 +7571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1', 'options': dict({ }), 'original_device_class': , @@ -7481,6 +7621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -7530,6 +7671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -7579,6 +7721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -7628,6 +7771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -7677,6 +7821,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overcurrent', 'options': dict({ }), 'original_device_class': , @@ -7726,6 +7871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheating', 'options': dict({ }), 'original_device_class': , @@ -7775,6 +7921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overpowering', 'options': dict({ }), 'original_device_class': , @@ -7824,6 +7971,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overvoltage', 'options': dict({ }), 'original_device_class': , @@ -7873,6 +8021,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -7922,6 +8071,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -7971,6 +8121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -8022,6 +8173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8078,6 +8230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8137,6 +8290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8196,6 +8350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8255,6 +8410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8311,6 +8467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8367,6 +8524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8423,6 +8581,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8479,6 +8638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8535,6 +8695,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8594,6 +8755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8653,6 +8815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8712,6 +8875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8768,6 +8932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8824,6 +8989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8880,6 +9046,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8936,6 +9103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -8987,6 +9155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -9035,6 +9204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -9083,6 +9253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -9144,6 +9315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -9205,6 +9377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud', 'options': dict({ }), 'original_device_class': , @@ -9254,6 +9427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart required', 'options': dict({ }), 'original_device_class': , @@ -9303,6 +9477,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -9354,6 +9529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9410,6 +9586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9466,6 +9643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9525,6 +9703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9582,6 +9761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last restart', 'options': dict({ }), 'original_device_class': , @@ -9633,6 +9813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Neutral current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9689,6 +9870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9745,6 +9927,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9801,6 +9984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9860,6 +10044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9919,6 +10104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9975,6 +10161,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10031,6 +10218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -10083,6 +10271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10139,6 +10328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10195,6 +10385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10251,6 +10442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10310,6 +10502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10369,6 +10562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10425,6 +10619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10481,6 +10676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -10533,6 +10729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10589,6 +10786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Apparent power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10645,6 +10843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10701,6 +10900,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10760,6 +10960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10819,6 +11020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10875,6 +11077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10931,6 +11134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power factor', 'options': dict({ }), 'original_device_class': , @@ -10983,6 +11187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11039,6 +11244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11095,6 +11301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -11148,6 +11355,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -11202,6 +11410,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Beta firmware', 'options': dict({ }), 'original_device_class': , @@ -11263,6 +11472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/shelly/snapshots/test_event.ambr b/tests/components/shelly/snapshots/test_event.ambr index b87436ba4aa..7bc6abbfa86 100644 --- a/tests/components/shelly/snapshots/test_event.ambr +++ b/tests/components/shelly/snapshots/test_event.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'test_script.js', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/shelly/snapshots/test_number.ambr b/tests/components/shelly/snapshots/test_number.ambr index d1f9a90a465..4640610de38 100644 --- a/tests/components/shelly/snapshots/test_number.ambr +++ b/tests/components/shelly/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External temperature', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': None, @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot intensity', 'options': dict({ }), 'original_device_class': None, @@ -200,6 +203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot intensity', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/shelly/snapshots/test_sensor.ambr b/tests/components/shelly/snapshots/test_sensor.ambr index 09628c598ea..4ce63f49a15 100644 --- a/tests/components/shelly/snapshots/test_sensor.ambr +++ b/tests/components/shelly/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': None, @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot level', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot vial', 'options': dict({ }), 'original_device_class': None, @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot level', 'options': dict({ }), 'original_device_class': None, @@ -330,6 +336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot vial', 'options': dict({ }), 'original_device_class': None, @@ -389,6 +396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger state', 'options': dict({ }), 'original_device_class': , @@ -450,6 +458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -506,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -562,6 +572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -618,6 +629,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -674,6 +686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -730,6 +743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -786,6 +800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -842,6 +857,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -898,6 +914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -952,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Session duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1007,6 +1025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Session energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1063,6 +1082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'test switch_0 energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1122,6 +1142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'test switch_0 energy consumed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1181,6 +1202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'test switch_0 energy returned', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1238,6 +1260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1291,6 +1314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rainfall', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/shelly/snapshots/test_switch.ambr b/tests/components/shelly/snapshots/test_switch.ambr index e376b7c4ad6..1637a22f480 100644 --- a/tests/components/shelly/snapshots/test_switch.ambr +++ b/tests/components/shelly/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away mode', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Left slot boost', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Right slot boost', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/shelly/test_binary_sensor.py b/tests/components/shelly/test_binary_sensor.py index c79da9d5427..9ce7ecd77df 100644 --- a/tests/components/shelly/test_binary_sensor.py +++ b/tests/components/shelly/test_binary_sensor.py @@ -3,7 +3,12 @@ from copy import deepcopy from unittest.mock import Mock -from aioshelly.const import MODEL_BLU_GATEWAY_G3, MODEL_MOTION, MODEL_PLUS_SMOKE +from aioshelly.const import ( + MODEL_BLU_GATEWAY_G3, + MODEL_FLOOD_G4, + MODEL_MOTION, + MODEL_PLUS_SMOKE, +) from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion @@ -612,7 +617,7 @@ async def test_rpc_flood_entities( snapshot: SnapshotAssertion, ) -> None: """Test RPC flood sensor entities.""" - await init_integration(hass, 4) + await init_integration(hass, 4, model=MODEL_FLOOD_G4) for entity in ("flood", "mute", "cable_unplugged"): entity_id = f"{BINARY_SENSOR_DOMAIN}.test_name_kitchen_{entity}" @@ -630,7 +635,7 @@ async def test_rpc_flood_cable_unplugged( monkeypatch: pytest.MonkeyPatch, ) -> None: """Test RPC flood cable unplugged entity.""" - await init_integration(hass, 4) + await init_integration(hass, 4, model=MODEL_FLOOD_G4) entity_id = f"{BINARY_SENSOR_DOMAIN}.test_name_kitchen_cable_unplugged" diff --git a/tests/components/simplefin/snapshots/test_binary_sensor.ambr b/tests/components/simplefin/snapshots/test_binary_sensor.ambr index 6602e6e35a9..a1a2c42377e 100644 --- a/tests/components/simplefin/snapshots/test_binary_sensor.ambr +++ b/tests/components/simplefin/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Possible error', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/simplefin/snapshots/test_sensor.ambr b/tests/components/simplefin/snapshots/test_sensor.ambr index 7f3e8d342fb..c2806eb89a9 100644 --- a/tests/components/simplefin/snapshots/test_sensor.ambr +++ b/tests/components/simplefin/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -127,6 +129,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -232,6 +236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -285,6 +290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -337,6 +343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -390,6 +397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -442,6 +450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -495,6 +504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -547,6 +557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -600,6 +611,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -652,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -705,6 +718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , @@ -757,6 +771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Balance', 'options': dict({ }), 'original_device_class': , @@ -810,6 +825,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Data age', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/siren/test_condition.py b/tests/components/siren/test_condition.py new file mode 100644 index 00000000000..c1c66d5e9d4 --- /dev/null +++ b/tests/components/siren/test_condition.py @@ -0,0 +1,173 @@ +"""Test siren conditions.""" + +from typing import Any + +import pytest + +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant + +from tests.components import ( + ConditionStateDescription, + assert_condition_gated_by_labs_flag, + create_target_condition, + parametrize_condition_states_all, + parametrize_condition_states_any, + parametrize_target_entities, + set_or_remove_state, + target_entities, +) + + +@pytest.fixture +async def target_sirens(hass: HomeAssistant) -> list[str]: + """Create multiple siren entities associated with different targets.""" + return (await target_entities(hass, "siren"))["included"] + + +@pytest.fixture +async def target_switches(hass: HomeAssistant) -> list[str]: + """Create multiple switch entities associated with different targets.""" + return (await target_entities(hass, "switch"))["included"] + + +@pytest.mark.parametrize( + "condition", + [ + "siren.is_off", + "siren.is_on", + ], +) +async def test_siren_conditions_gated_by_labs_flag( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, condition: str +) -> None: + """Test the siren conditions are gated by the labs flag.""" + await assert_condition_gated_by_labs_flag(hass, caplog, condition) + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("siren"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_any( + condition="siren.is_on", + target_states=[STATE_ON], + other_states=[STATE_OFF], + ), + *parametrize_condition_states_any( + condition="siren.is_off", + target_states=[STATE_OFF], + other_states=[STATE_ON], + ), + ], +) +async def test_siren_state_condition_behavior_any( + hass: HomeAssistant, + target_sirens: list[str], + target_switches: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the siren state condition with the 'any' behavior.""" + other_entity_ids = set(target_sirens) - {entity_id} + + # Set all sirens, including the tested siren, to the initial state + for eid in target_sirens: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="any", + ) + + # Set state for switches to ensure that they don't impact the condition + for state in states: + for eid in target_switches: + set_or_remove_state(hass, eid, state["included"]) + await hass.async_block_till_done() + assert condition(hass) is False + + for state in states: + included_state = state["included"] + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + # Check if changing other sirens also passes the condition + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true"] + + +@pytest.mark.usefixtures("enable_labs_preview_features") +@pytest.mark.parametrize( + ("condition_target_config", "entity_id", "entities_in_target"), + parametrize_target_entities("siren"), +) +@pytest.mark.parametrize( + ("condition", "condition_options", "states"), + [ + *parametrize_condition_states_all( + condition="siren.is_on", + target_states=[STATE_ON], + other_states=[STATE_OFF], + ), + *parametrize_condition_states_all( + condition="siren.is_off", + target_states=[STATE_OFF], + other_states=[STATE_ON], + ), + ], +) +async def test_siren_state_condition_behavior_all( + hass: HomeAssistant, + target_sirens: list[str], + condition_target_config: dict, + entity_id: str, + entities_in_target: int, + condition: str, + condition_options: dict[str, Any], + states: list[ConditionStateDescription], +) -> None: + """Test the siren state condition with the 'all' behavior.""" + # Set state for two switches to ensure that they don't impact the condition + hass.states.async_set("switch.label_switch_1", STATE_OFF) + hass.states.async_set("switch.label_switch_2", STATE_ON) + other_entity_ids = set(target_sirens) - {entity_id} + + # Set all sirens, including the tested siren, to the initial state + for eid in target_sirens: + set_or_remove_state(hass, eid, states[0]["included"]) + await hass.async_block_till_done() + + condition = await create_target_condition( + hass, + condition=condition, + target=condition_target_config, + behavior="all", + ) + + for state in states: + included_state = state["included"] + + set_or_remove_state(hass, entity_id, included_state) + await hass.async_block_till_done() + assert condition(hass) == state["condition_true_first_entity"] + + for other_entity_id in other_entity_ids: + set_or_remove_state(hass, other_entity_id, included_state) + await hass.async_block_till_done() + + assert condition(hass) == state["condition_true"] diff --git a/tests/components/siren/test_trigger.py b/tests/components/siren/test_trigger.py index 5bd5026c465..1187b5365e2 100644 --- a/tests/components/siren/test_trigger.py +++ b/tests/components/siren/test_trigger.py @@ -1,8 +1,6 @@ """Test siren triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, STATE_OFF, STATE_ from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -20,21 +18,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_sirens(hass: HomeAssistant) -> list[str]: """Create multiple siren entities associated with different targets.""" @@ -61,7 +44,7 @@ async def test_siren_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -90,7 +73,7 @@ async def test_siren_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the siren state trigger fires when any siren state changes to a specific state.""" other_entity_ids = set(target_sirens) - {entity_id} @@ -119,7 +102,7 @@ async def test_siren_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -148,7 +131,7 @@ async def test_siren_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the siren state trigger fires when the first siren changes to a specific state.""" other_entity_ids = set(target_sirens) - {entity_id} @@ -176,7 +159,7 @@ async def test_siren_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -205,7 +188,7 @@ async def test_siren_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the siren state trigger fires when the last siren changes to a specific state.""" other_entity_ids = set(target_sirens) - {entity_id} diff --git a/tests/components/sleep_as_android/snapshots/test_event.ambr b/tests/components/sleep_as_android/snapshots/test_event.ambr index 2fe6494f140..34d170952bd 100644 --- a/tests/components/sleep_as_android/snapshots/test_event.ambr +++ b/tests/components/sleep_as_android/snapshots/test_event.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm clock', 'options': dict({ }), 'original_device_class': None, @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Jet lag prevention', 'options': dict({ }), 'original_device_class': None, @@ -150,6 +152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lullaby', 'options': dict({ }), 'original_device_class': None, @@ -209,6 +212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep health', 'options': dict({ }), 'original_device_class': None, @@ -270,6 +274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep phase', 'options': dict({ }), 'original_device_class': None, @@ -333,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep tracking', 'options': dict({ }), 'original_device_class': , @@ -394,6 +400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart wake-up', 'options': dict({ }), 'original_device_class': None, @@ -455,6 +462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound recognition', 'options': dict({ }), 'original_device_class': None, @@ -517,6 +525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User notification', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sleep_as_android/snapshots/test_sensor.ambr b/tests/components/sleep_as_android/snapshots/test_sensor.ambr index fb7f7554689..f3475bd66d0 100644 --- a/tests/components/sleep_as_android/snapshots/test_sensor.ambr +++ b/tests/components/sleep_as_android/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm label', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Next alarm', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/slide_local/snapshots/test_button.ambr b/tests/components/slide_local/snapshots/test_button.ambr index 9ab1ff9623d..c4e849b3c60 100644 --- a/tests/components/slide_local/snapshots/test_button.ambr +++ b/tests/components/slide_local/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calibrate', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/slide_local/snapshots/test_cover.ambr b/tests/components/slide_local/snapshots/test_cover.ambr index 09d182a4bb6..9bf6c5ad00f 100644 --- a/tests/components/slide_local/snapshots/test_cover.ambr +++ b/tests/components/slide_local/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/slide_local/snapshots/test_switch.ambr b/tests/components/slide_local/snapshots/test_switch.ambr index ddfe7151f44..3e8a968f305 100644 --- a/tests/components/slide_local/snapshots/test_switch.ambr +++ b/tests/components/slide_local/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TouchGo', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/sma/__init__.py b/tests/components/sma/__init__.py index eebaf43ccd8..99ae823dd97 100644 --- a/tests/components/sma/__init__.py +++ b/tests/components/sma/__init__.py @@ -35,6 +35,14 @@ MOCK_USER_REAUTH = { CONF_PASSWORD: "new_password", } +MOCK_USER_RECONFIGURE = { + CONF_HOST: "1.1.1.2", + CONF_SSL: True, + CONF_VERIFY_SSL: False, + CONF_GROUP: "user", +} + + MOCK_DHCP_DISCOVERY_INPUT = { CONF_SSL: True, CONF_VERIFY_SSL: False, diff --git a/tests/components/sma/snapshots/test_sensor.ambr b/tests/components/sma/snapshots/test_sensor.ambr index 257f07d1a32..b4281018b3e 100644 --- a/tests/components/sma/snapshots/test_sensor.ambr +++ b/tests/components/sma/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Capacity A', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Capacity B', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Capacity C', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Capacity Total', 'options': dict({ }), 'original_device_class': None, @@ -218,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charge A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -274,6 +279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charge B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -330,6 +336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charge C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -386,6 +393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charge Total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -442,6 +450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charging Voltage A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -498,6 +507,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charging Voltage B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -554,6 +564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Charging Voltage C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -610,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Current A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -666,6 +678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Current B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -722,6 +735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Current C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -778,6 +792,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Discharge A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -834,6 +849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Discharge B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -890,6 +906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Discharge C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -946,6 +963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Discharge Total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1002,6 +1020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Charge A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1058,6 +1077,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Charge B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1114,6 +1134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Charge C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1170,6 +1191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Charge Total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1226,6 +1248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Discharge A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1282,6 +1305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Discharge B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1338,6 +1362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Discharge C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1394,6 +1419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Power Discharge Total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1450,6 +1476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery SOC A', 'options': dict({ }), 'original_device_class': , @@ -1503,6 +1530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery SOC B', 'options': dict({ }), 'original_device_class': , @@ -1556,6 +1584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery SOC C', 'options': dict({ }), 'original_device_class': , @@ -1609,6 +1638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery SOC Total', 'options': dict({ }), 'original_device_class': , @@ -1660,6 +1690,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Status Operating Mode', 'options': dict({ }), 'original_device_class': None, @@ -1710,6 +1741,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Temp A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1766,6 +1798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Temp B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1822,6 +1855,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Temp C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1878,6 +1912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Voltage A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1934,6 +1969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Voltage B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1990,6 +2026,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Battery Voltage C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2046,6 +2083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Current L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2102,6 +2140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Current L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2158,6 +2197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Current L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2214,6 +2254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Current Total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2270,6 +2311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Daily Yield', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2326,6 +2368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2382,6 +2425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Apparent Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2438,6 +2482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Apparent Power L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2494,6 +2539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Apparent Power L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2550,6 +2596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Apparent Power L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2604,6 +2651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Connection Status', 'options': dict({ }), 'original_device_class': None, @@ -2654,6 +2702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2710,6 +2759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Power Factor', 'options': dict({ }), 'original_device_class': , @@ -2760,6 +2810,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Power Factor Excitation', 'options': dict({ }), 'original_device_class': None, @@ -2810,6 +2861,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Reactive Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2866,6 +2918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Reactive Power L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2922,6 +2975,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Reactive Power L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2978,6 +3032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Reactive Power L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3032,6 +3087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Grid Relay Status', 'options': dict({ }), 'original_device_class': None, @@ -3082,6 +3138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Insulation Residual Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3136,6 +3193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Inverter Condition', 'options': dict({ }), 'original_device_class': None, @@ -3186,6 +3244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Inverter Power Limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3240,6 +3299,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Inverter System Init', 'options': dict({ }), 'original_device_class': None, @@ -3290,6 +3350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Active Power Draw L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3346,6 +3407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Active Power Draw L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3402,6 +3464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Active Power Draw L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3458,6 +3521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Active Power Feed L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3514,6 +3578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Active Power Feed L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3570,6 +3635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Active Power Feed L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3626,6 +3692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Current Consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3682,6 +3749,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Current L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3738,6 +3806,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Current L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3794,6 +3863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Current L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3850,6 +3920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3906,6 +3977,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Power Absorbed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3962,6 +4034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Power Supplied', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4018,6 +4091,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Total Absorbed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4074,6 +4148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Total Consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4130,6 +4205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Total Yield', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4186,6 +4262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Voltage L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4242,6 +4319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Voltage L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4298,6 +4376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Metering Voltage L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4352,6 +4431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Operating Status', 'options': dict({ }), 'original_device_class': None, @@ -4400,6 +4480,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Operating Status General', 'options': dict({ }), 'original_device_class': None, @@ -4450,6 +4531,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Optimizer Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4506,6 +4588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Optimizer Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4562,6 +4645,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Optimizer Temp', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4618,6 +4702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Optimizer Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4674,6 +4759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Power L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4730,6 +4816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Power L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4786,6 +4873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Power L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4842,6 +4930,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Current A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4898,6 +4987,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Current B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4954,6 +5044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Current C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5010,6 +5101,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Gen Meter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5066,6 +5158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Isolation Resistance', 'options': dict({ }), 'original_device_class': None, @@ -5118,6 +5211,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5174,6 +5268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Power A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5230,6 +5325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Power B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5286,6 +5382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Power C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5342,6 +5439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Voltage A', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5398,6 +5496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Voltage B', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5454,6 +5553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name PV Voltage C', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5510,6 +5610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Secure Power Supply Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5566,6 +5667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Secure Power Supply Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5622,6 +5724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Secure Power Supply Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5676,6 +5779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Status', 'options': dict({ }), 'original_device_class': None, @@ -5726,6 +5830,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Total Yield', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5782,6 +5887,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Voltage L1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5838,6 +5944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Voltage L2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5894,6 +6001,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SMA Device Name Voltage L3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/sma/test_config_flow.py b/tests/components/sma/test_config_flow.py index 63130c5cf35..f927f9979da 100644 --- a/tests/components/sma/test_config_flow.py +++ b/tests/components/sma/test_config_flow.py @@ -3,11 +3,12 @@ from unittest.mock import AsyncMock, MagicMock, patch from pysma import SmaAuthenticationException, SmaConnectionException, SmaReadException +from pysma.helpers import DeviceInfo import pytest -from homeassistant.components.sma.const import DOMAIN +from homeassistant.components.sma.const import CONF_GROUP, DOMAIN from homeassistant.config_entries import SOURCE_DHCP, SOURCE_USER -from homeassistant.const import CONF_MAC +from homeassistant.const import CONF_HOST, CONF_MAC, CONF_SSL, CONF_VERIFY_SSL from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers.device_registry import format_mac @@ -19,6 +20,7 @@ from . import ( MOCK_DHCP_DISCOVERY_INPUT, MOCK_USER_INPUT, MOCK_USER_REAUTH, + MOCK_USER_RECONFIGURE, ) from tests.conftest import MockConfigEntry @@ -311,3 +313,109 @@ async def test_reauth_flow_exceptions( assert result["type"] is FlowResultType.ABORT assert result["reason"] == "reauth_successful" + + +async def test_full_flow_reconfigure( + hass: HomeAssistant, + mock_setup_entry: MockConfigEntry, + mock_sma_client: AsyncMock, +) -> None: + """Test the full flow of the config flow.""" + entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT, unique_id="123456789") + entry.add_to_hass(hass) + result = await entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=MOCK_USER_RECONFIGURE, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert entry.data[CONF_HOST] == "1.1.1.2" + assert entry.data[CONF_SSL] is True + assert entry.data[CONF_VERIFY_SSL] is False + assert entry.data[CONF_GROUP] == "user" + assert len(mock_setup_entry.mock_calls) == 1 + + +@pytest.mark.parametrize( + ("exception", "error"), + [ + (SmaConnectionException, "cannot_connect"), + (SmaAuthenticationException, "invalid_auth"), + (SmaReadException, "cannot_retrieve_device_info"), + (Exception, "unknown"), + ], +) +async def test_full_flow_reconfigure_exceptions( + hass: HomeAssistant, + mock_setup_entry: MockConfigEntry, + mock_sma_client: AsyncMock, + exception: Exception, + error: str, +) -> None: + """Test we handle cannot connect error and recover from it.""" + entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT, unique_id="123456789") + entry.add_to_hass(hass) + result = await entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + + mock_sma_client.new_session.side_effect = exception + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + MOCK_USER_RECONFIGURE, + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": error} + + mock_sma_client.new_session.side_effect = None + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=MOCK_USER_RECONFIGURE, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert entry.data[CONF_HOST] == "1.1.1.2" + assert entry.data[CONF_SSL] is True + assert entry.data[CONF_VERIFY_SSL] is False + assert entry.data[CONF_GROUP] == "user" + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_reconfigure_mismatch_id( + hass: HomeAssistant, + mock_setup_entry: MockConfigEntry, + mock_sma_client: AsyncMock, +) -> None: + """Test when a mismatch happens during reconfigure.""" + entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_INPUT, unique_id="123456789") + entry.add_to_hass(hass) + result = await entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "reconfigure" + + # New device, on purpose to demonstrate we can't switch + different_device = DeviceInfo( + manufacturer="SMA", + name="Different SMA Device", + type="Sunny Boy 5.0", + serial=987654321, + sw_version="2.0.0", + ) + mock_sma_client.device_info = AsyncMock(return_value=different_device) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=MOCK_USER_RECONFIGURE, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "unique_id_mismatch" diff --git a/tests/components/smarla/snapshots/test_number.ambr b/tests/components/smarla/snapshots/test_number.ambr index 50312e09920..1930a825e59 100644 --- a/tests/components/smarla/snapshots/test_number.ambr +++ b/tests/components/smarla/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intensity', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smarla/snapshots/test_sensor.ambr b/tests/components/smarla/snapshots/test_sensor.ambr index 88d6a6ecea6..a2b9c991da9 100644 --- a/tests/components/smarla/snapshots/test_sensor.ambr +++ b/tests/components/smarla/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activity', 'options': dict({ }), 'original_device_class': None, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Amplitude', 'options': dict({ }), 'original_device_class': None, @@ -125,6 +127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Period', 'options': dict({ }), 'original_device_class': None, @@ -177,6 +180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Swing count', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smarla/snapshots/test_switch.ambr b/tests/components/smarla/snapshots/test_switch.ambr index f73981b55ea..5bc41c707fd 100644 --- a/tests/components/smarla/snapshots/test_switch.ambr +++ b/tests/components/smarla/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smart Mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_binary_sensor.ambr b/tests/components/smartthings/snapshots/test_binary_sensor.ambr index 1a3d1ca0d90..5f2e82d560a 100644 --- a/tests/components/smartthings/snapshots/test_binary_sensor.ambr +++ b/tests/components/smartthings/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -313,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -362,6 +369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -411,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -459,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -508,6 +518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -557,6 +568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -605,6 +617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -653,6 +666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -702,6 +716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -750,6 +765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -798,6 +814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -847,6 +864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -895,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -943,6 +962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -992,6 +1012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1040,6 +1061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -1088,6 +1110,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -1137,6 +1160,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1185,6 +1209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter status', 'options': dict({ }), 'original_device_class': , @@ -1234,6 +1259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer door', 'options': dict({ }), 'original_device_class': , @@ -1283,6 +1309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge door', 'options': dict({ }), 'original_device_class': , @@ -1332,6 +1359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CoolSelect+ door', 'options': dict({ }), 'original_device_class': , @@ -1381,6 +1409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter status', 'options': dict({ }), 'original_device_class': , @@ -1430,6 +1459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer door', 'options': dict({ }), 'original_device_class': , @@ -1479,6 +1509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge door', 'options': dict({ }), 'original_device_class': , @@ -1528,6 +1559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter status', 'options': dict({ }), 'original_device_class': , @@ -1577,6 +1609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer door', 'options': dict({ }), 'original_device_class': , @@ -1626,6 +1659,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge door', 'options': dict({ }), 'original_device_class': , @@ -1675,6 +1709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -1724,6 +1759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -1772,6 +1808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1821,6 +1858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -1869,6 +1907,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -1917,6 +1956,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1966,6 +2006,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2014,6 +2055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2062,6 +2104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keep fresh mode active', 'options': dict({ }), 'original_device_class': None, @@ -2110,6 +2153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -2159,6 +2203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2207,6 +2252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2255,6 +2301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -2304,6 +2351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2352,6 +2400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrinkle prevent active', 'options': dict({ }), 'original_device_class': None, @@ -2400,6 +2449,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2448,6 +2498,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -2497,6 +2548,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2545,6 +2597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrinkle prevent active', 'options': dict({ }), 'original_device_class': None, @@ -2593,6 +2646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2641,6 +2695,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -2690,6 +2745,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2738,6 +2794,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrinkle prevent active', 'options': dict({ }), 'original_device_class': None, @@ -2786,6 +2843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2834,6 +2892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -2883,6 +2942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -2931,6 +2991,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2979,6 +3040,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -3028,6 +3090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -3076,6 +3139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3124,6 +3188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -3173,6 +3238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -3221,6 +3287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -3270,6 +3337,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -3318,6 +3386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -3367,6 +3436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remote control', 'options': dict({ }), 'original_device_class': None, @@ -3415,6 +3485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper washer remote control', 'options': dict({ }), 'original_device_class': None, @@ -3463,6 +3534,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -3512,6 +3584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence', 'options': dict({ }), 'original_device_class': , @@ -3561,6 +3634,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas', 'options': dict({ }), 'original_device_class': , @@ -3610,6 +3684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Presence', 'options': dict({ }), 'original_device_class': , @@ -3659,6 +3734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3708,6 +3784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Acceleration', 'options': dict({ }), 'original_device_class': , @@ -3757,6 +3834,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_button.ambr b/tests/components/smartthings/snapshots/test_button.ambr index 1c0a3d7781f..849c06a45b2 100644 --- a/tests/components/smartthings/snapshots/test_button.ambr +++ b/tests/components/smartthings/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset water filter', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset water filter', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset water filter', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_climate.ambr b/tests/components/smartthings/snapshots/test_climate.ambr index e8250a6d1a2..f2f1ca37d7f 100644 --- a/tests/components/smartthings/snapshots/test_climate.ambr +++ b/tests/components/smartthings/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -92,6 +93,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -182,6 +184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -279,6 +282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -361,6 +365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -476,6 +481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -601,6 +607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -708,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -785,6 +793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -853,6 +862,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -921,6 +931,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -988,6 +999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1058,6 +1070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1131,6 +1144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1195,6 +1209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1259,6 +1274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1334,6 +1350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1413,6 +1430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_cover.ambr b/tests/components/smartthings/snapshots/test_cover.ambr index ff34a2a1fea..7f97081c72f 100644 --- a/tests/components/smartthings/snapshots/test_cover.ambr +++ b/tests/components/smartthings/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_event.ambr b/tests/components/smartthings/snapshots/test_event.ambr index ef074b24ce5..8e72ba07229 100644 --- a/tests/components/smartthings/snapshots/test_event.ambr +++ b/tests/components/smartthings/snapshots/test_event.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'button1', 'options': dict({ }), 'original_device_class': , @@ -87,6 +88,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'button2', 'options': dict({ }), 'original_device_class': , @@ -148,6 +150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'button3', 'options': dict({ }), 'original_device_class': , @@ -209,6 +212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'button4', 'options': dict({ }), 'original_device_class': , @@ -270,6 +274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'button5', 'options': dict({ }), 'original_device_class': , @@ -331,6 +336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'button6', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_fan.ambr b/tests/components/smartthings/snapshots/test_fan.ambr index 1219c58dd42..2bdad0b71e2 100644 --- a/tests/components/smartthings/snapshots/test_fan.ambr +++ b/tests/components/smartthings/snapshots/test_fan.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -87,6 +88,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -148,6 +150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_light.ambr b/tests/components/smartthings/snapshots/test_light.ambr index c54b40ffab9..16ee4ad3a5f 100644 --- a/tests/components/smartthings/snapshots/test_light.ambr +++ b/tests/components/smartthings/snapshots/test_light.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -95,6 +96,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -153,6 +155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -215,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -297,6 +301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_lock.ambr b/tests/components/smartthings/snapshots/test_lock.ambr index c2cdf9c6375..820cee78310 100644 --- a/tests/components/smartthings/snapshots/test_lock.ambr +++ b/tests/components/smartthings/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_media_player.ambr b/tests/components/smartthings/snapshots/test_media_player.ambr index 9b7bcba70fb..9e11b4e283c 100644 --- a/tests/components/smartthings/snapshots/test_media_player.ambr +++ b/tests/components/smartthings/snapshots/test_media_player.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -91,6 +92,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -146,6 +148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -201,6 +204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -257,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -314,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_number.ambr b/tests/components/smartthings/snapshots/test_number.ambr index 0b600387033..d495f769a88 100644 --- a/tests/components/smartthings/snapshots/test_number.ambr +++ b/tests/components/smartthings/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan speed', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer temperature', 'options': dict({ }), 'original_device_class': , @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge temperature', 'options': dict({ }), 'original_device_class': , @@ -200,6 +203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer temperature', 'options': dict({ }), 'original_device_class': , @@ -259,6 +263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge temperature', 'options': dict({ }), 'original_device_class': , @@ -318,6 +323,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer temperature', 'options': dict({ }), 'original_device_class': , @@ -377,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge temperature', 'options': dict({ }), 'original_device_class': , @@ -436,6 +443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ }), 'original_device_class': , @@ -495,6 +503,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse cycles', 'options': dict({ }), 'original_device_class': None, @@ -553,6 +562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse cycles', 'options': dict({ }), 'original_device_class': None, @@ -611,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rinse cycles', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_scene.ambr b/tests/components/smartthings/snapshots/test_scene.ambr index e7b2ac7b9f9..afd71b98841 100644 --- a/tests/components/smartthings/snapshots/test_scene.ambr +++ b/tests/components/smartthings/snapshots/test_scene.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Home', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_select.ambr b/tests/components/smartthings/snapshots/test_select.ambr index fb99983a74b..e5ac4227f5f 100644 --- a/tests/components/smartthings/snapshots/test_select.ambr +++ b/tests/components/smartthings/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dust filter alarm threshold', 'options': dict({ }), 'original_device_class': None, @@ -88,6 +89,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dust filter alarm threshold', 'options': dict({ }), 'original_device_class': None, @@ -148,6 +150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lamp', 'options': dict({ }), 'original_device_class': None, @@ -206,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lamp', 'options': dict({ }), 'original_device_class': None, @@ -263,6 +267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lamp', 'options': dict({ }), 'original_device_class': None, @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lamp', 'options': dict({ }), 'original_device_class': None, @@ -377,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lamp', 'options': dict({ }), 'original_device_class': None, @@ -434,6 +441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lamp', 'options': dict({ }), 'original_device_class': None, @@ -492,6 +500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -551,6 +560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -610,6 +620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -669,6 +680,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -728,6 +740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -787,6 +800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -846,6 +860,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -908,6 +923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soil level', 'options': dict({ }), 'original_device_class': None, @@ -973,6 +989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spin level', 'options': dict({ }), 'original_device_class': None, @@ -1038,6 +1055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ }), 'original_device_class': None, @@ -1100,6 +1118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1163,6 +1182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spin level', 'options': dict({ }), 'original_device_class': None, @@ -1230,6 +1250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ }), 'original_device_class': None, @@ -1293,6 +1314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1353,6 +1375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Detergent dispense amount', 'options': dict({ }), 'original_device_class': None, @@ -1414,6 +1437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flexible compartment dispense amount', 'options': dict({ }), 'original_device_class': None, @@ -1478,6 +1502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spin level', 'options': dict({ }), 'original_device_class': None, @@ -1545,6 +1570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ }), 'original_device_class': None, @@ -1608,6 +1634,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1667,6 +1694,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_sensor.ambr b/tests/components/smartthings/snapshots/test_sensor.ambr index 4abe995c6b9..b13d94dc0ee 100644 --- a/tests/components/smartthings/snapshots/test_sensor.ambr +++ b/tests/components/smartthings/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ }), 'original_device_class': , @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -236,6 +240,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -289,6 +294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -342,6 +348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -398,6 +405,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -449,6 +457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -502,6 +511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -555,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -611,6 +622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds parts', 'options': dict({ }), 'original_device_class': , @@ -664,6 +676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -720,6 +733,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -776,6 +790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -830,6 +845,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -882,6 +898,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -943,6 +960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm', 'options': dict({ }), 'original_device_class': , @@ -998,6 +1016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1050,6 +1069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1104,6 +1124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1156,6 +1177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1212,6 +1234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -1264,6 +1287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ }), 'original_device_class': , @@ -1317,6 +1341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1368,6 +1393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odor sensor', 'options': dict({ }), 'original_device_class': None, @@ -1418,6 +1444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -1471,6 +1498,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -1531,6 +1559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10 health concern', 'options': dict({ }), 'original_device_class': , @@ -1597,6 +1626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1 health concern', 'options': dict({ }), 'original_device_class': , @@ -1656,6 +1686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -1716,6 +1747,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5 health concern', 'options': dict({ }), 'original_device_class': , @@ -1775,6 +1807,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1831,6 +1864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1887,6 +1921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1943,6 +1978,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1999,6 +2035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2052,6 +2089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2110,6 +2148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2166,6 +2205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2220,6 +2260,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -2271,6 +2312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2327,6 +2369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2383,6 +2426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2439,6 +2483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2497,6 +2542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2553,6 +2599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2609,6 +2656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2665,6 +2713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2721,6 +2770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2774,6 +2824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2832,6 +2883,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2888,6 +2940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2942,6 +2995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -2993,6 +3047,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3049,6 +3104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3105,6 +3161,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3161,6 +3218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -3214,6 +3272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3272,6 +3331,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3328,6 +3388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3382,6 +3443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -3433,6 +3495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3489,6 +3552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3545,6 +3609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3601,6 +3666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -3654,6 +3720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3712,6 +3779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3768,6 +3836,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3822,6 +3891,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -3873,6 +3943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -3925,6 +3996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -3978,6 +4050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -4031,6 +4104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4090,6 +4164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating state', 'options': dict({ }), 'original_device_class': , @@ -4149,6 +4224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 1 heating mode', 'options': dict({ }), 'original_device_class': , @@ -4203,6 +4279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 1 level', 'options': dict({ }), 'original_device_class': None, @@ -4257,6 +4334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 2 heating mode', 'options': dict({ }), 'original_device_class': , @@ -4311,6 +4389,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 2 level', 'options': dict({ }), 'original_device_class': None, @@ -4365,6 +4444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 3 heating mode', 'options': dict({ }), 'original_device_class': , @@ -4419,6 +4499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 3 level', 'options': dict({ }), 'original_device_class': None, @@ -4473,6 +4554,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 4 heating mode', 'options': dict({ }), 'original_device_class': , @@ -4527,6 +4609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner 4 level', 'options': dict({ }), 'original_device_class': None, @@ -4581,6 +4664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating state', 'options': dict({ }), 'original_device_class': , @@ -4637,6 +4721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -4689,6 +4774,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4745,6 +4831,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4801,6 +4888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4857,6 +4945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter usage', 'options': dict({ }), 'original_device_class': None, @@ -4909,6 +4998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -4962,6 +5052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -5022,6 +5113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10 health concern', 'options': dict({ }), 'original_device_class': , @@ -5088,6 +5180,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1 health concern', 'options': dict({ }), 'original_device_class': , @@ -5147,6 +5240,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -5207,6 +5301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5 health concern', 'options': dict({ }), 'original_device_class': , @@ -5266,6 +5361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5324,6 +5420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5378,6 +5475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -5447,6 +5545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -5521,6 +5620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -5603,6 +5703,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oven mode', 'options': dict({ }), 'original_device_class': , @@ -5679,6 +5780,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5734,6 +5836,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5788,6 +5891,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -5857,6 +5961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -5931,6 +6036,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -6013,6 +6119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oven mode', 'options': dict({ }), 'original_device_class': , @@ -6089,6 +6196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6144,6 +6252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6198,6 +6307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -6267,6 +6377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -6341,6 +6452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -6423,6 +6535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oven mode', 'options': dict({ }), 'original_device_class': , @@ -6499,6 +6612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6554,6 +6668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6608,6 +6723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -6677,6 +6793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -6751,6 +6868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -6810,6 +6928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operating state', 'options': dict({ }), 'original_device_class': , @@ -6891,6 +7010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oven mode', 'options': dict({ }), 'original_device_class': , @@ -6967,6 +7087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7022,6 +7143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7076,6 +7198,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -7127,6 +7250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7183,6 +7307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7239,6 +7364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7313,6 +7439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -7387,6 +7514,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -7469,6 +7597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oven mode', 'options': dict({ }), 'original_device_class': , @@ -7547,6 +7676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7605,6 +7735,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7659,6 +7790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7714,6 +7846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7770,6 +7903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7826,6 +7960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7882,6 +8017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7938,6 +8074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7994,6 +8131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8050,6 +8188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8108,6 +8247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8164,6 +8304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water filter usage', 'options': dict({ }), 'original_device_class': None, @@ -8216,6 +8357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8272,6 +8414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8328,6 +8471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8384,6 +8528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8440,6 +8585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8496,6 +8642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8554,6 +8701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8610,6 +8758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water filter usage', 'options': dict({ }), 'original_device_class': None, @@ -8662,6 +8811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8718,6 +8868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8774,6 +8925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8830,6 +8982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freezer temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8886,6 +9039,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fridge temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8942,6 +9096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9000,6 +9155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9056,6 +9212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water filter usage', 'options': dict({ }), 'original_device_class': None, @@ -9108,6 +9265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9164,6 +9322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9220,6 +9379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9276,6 +9436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9334,6 +9495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9390,6 +9552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9444,6 +9607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -9503,6 +9667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning mode', 'options': dict({ }), 'original_device_class': , @@ -9562,6 +9727,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9618,6 +9784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9674,6 +9841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9741,6 +9909,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Movement', 'options': dict({ }), 'original_device_class': , @@ -9804,6 +9973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9862,6 +10032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9923,6 +10094,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turbo mode', 'options': dict({ }), 'original_device_class': , @@ -9978,6 +10150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -10037,6 +10210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning mode', 'options': dict({ }), 'original_device_class': , @@ -10107,6 +10281,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Movement', 'options': dict({ }), 'original_device_class': , @@ -10175,6 +10350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turbo mode', 'options': dict({ }), 'original_device_class': , @@ -10232,6 +10408,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10288,6 +10465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10344,6 +10522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10400,6 +10579,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10458,6 +10638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10517,6 +10698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': , @@ -10572,6 +10754,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10628,6 +10811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10684,6 +10868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10740,6 +10925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10798,6 +10984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10857,6 +11044,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': , @@ -10912,6 +11100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10968,6 +11157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11024,6 +11214,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11080,6 +11271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11138,6 +11330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11197,6 +11390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': , @@ -11250,6 +11444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -11301,6 +11496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11357,6 +11553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11413,6 +11610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11480,6 +11678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -11547,6 +11746,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -11603,6 +11803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11661,6 +11862,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11715,6 +11917,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -11766,6 +11969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11822,6 +12026,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11878,6 +12083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11945,6 +12151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -12012,6 +12219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -12068,6 +12276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12126,6 +12335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12182,6 +12392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12236,6 +12447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -12287,6 +12499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12343,6 +12556,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12399,6 +12613,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12471,6 +12686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -12543,6 +12759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -12599,6 +12816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12657,6 +12875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12711,6 +12930,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -12762,6 +12982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12818,6 +13039,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12874,6 +13096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12946,6 +13169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -13018,6 +13242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -13074,6 +13299,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13132,6 +13358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13186,6 +13413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -13237,6 +13465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13293,6 +13522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13349,6 +13579,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13421,6 +13652,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -13493,6 +13725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -13549,6 +13782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13607,6 +13841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13661,6 +13896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -13712,6 +13948,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13768,6 +14005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13824,6 +14062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13896,6 +14135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -13968,6 +14208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -14024,6 +14265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14082,6 +14324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14136,6 +14379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -14187,6 +14431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14243,6 +14488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14299,6 +14545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14372,6 +14619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -14445,6 +14693,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -14501,6 +14750,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14559,6 +14809,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14613,6 +14864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -14664,6 +14916,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14720,6 +14973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14776,6 +15030,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14849,6 +15104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -14922,6 +15178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -14978,6 +15235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15036,6 +15294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15090,6 +15349,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -15141,6 +15401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15197,6 +15458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15253,6 +15515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saved', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15326,6 +15589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -15399,6 +15663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -15455,6 +15720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15513,6 +15779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15569,6 +15836,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15623,6 +15891,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -15691,6 +15960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -15764,6 +16034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -15818,6 +16089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completion time', 'options': dict({ }), 'original_device_class': , @@ -15886,6 +16158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Job state', 'options': dict({ }), 'original_device_class': , @@ -15959,6 +16232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Machine state', 'options': dict({ }), 'original_device_class': , @@ -16013,6 +16287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper washer completion time', 'options': dict({ }), 'original_device_class': , @@ -16081,6 +16356,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper washer job state', 'options': dict({ }), 'original_device_class': , @@ -16154,6 +16430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper washer machine state', 'options': dict({ }), 'original_device_class': , @@ -16210,6 +16487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16266,6 +16544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -16319,6 +16598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16375,6 +16655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -16428,6 +16709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': , @@ -16480,6 +16762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link quality', 'options': dict({ }), 'original_device_class': None, @@ -16531,6 +16814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -16584,6 +16868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16643,6 +16928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas meter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16697,6 +16983,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas meter calorific', 'options': dict({ }), 'original_device_class': None, @@ -16745,6 +17032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas meter time', 'options': dict({ }), 'original_device_class': , @@ -16796,6 +17084,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link quality', 'options': dict({ }), 'original_device_class': None, @@ -16847,6 +17136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -16900,6 +17190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16954,6 +17245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17006,6 +17298,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17062,6 +17355,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17118,6 +17412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17172,6 +17467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17224,6 +17520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Atmospheric pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17281,6 +17578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17333,6 +17631,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -17386,6 +17685,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17440,6 +17740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17492,6 +17793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17546,6 +17848,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'X coordinate', 'options': dict({ }), 'original_device_class': None, @@ -17594,6 +17897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Y coordinate', 'options': dict({ }), 'original_device_class': None, @@ -17642,6 +17946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Z coordinate', 'options': dict({ }), 'original_device_class': None, @@ -17692,6 +17997,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -17745,6 +18051,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17799,6 +18106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air conditioner mode', 'options': dict({ }), 'original_device_class': None, @@ -17847,6 +18155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooling setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -17900,6 +18209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17952,6 +18262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18008,6 +18319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy difference', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18064,6 +18376,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brightness intensity', 'options': dict({ }), 'original_device_class': None, @@ -18114,6 +18427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TV channel', 'options': dict({ }), 'original_device_class': None, @@ -18162,6 +18476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TV channel name', 'options': dict({ }), 'original_device_class': None, @@ -18210,6 +18525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -18262,6 +18578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -18316,6 +18633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -18366,6 +18684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_switch.ambr b/tests/components/smartthings/snapshots/test_switch.ambr index c1833296ef9..73fb7dd542b 100644 --- a/tests/components/smartthings/snapshots/test_switch.ambr +++ b/tests/components/smartthings/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound effect', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display lighting', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound effect', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sabbath mode', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cubed ice', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power cool', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power freeze', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sabbath mode', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cubed ice', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power cool', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power freeze', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cubed ice', 'options': dict({ }), 'original_device_class': None, @@ -692,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ice Bites', 'options': dict({ }), 'original_device_class': None, @@ -740,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power cool', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power freeze', 'options': dict({ }), 'original_device_class': None, @@ -836,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sabbath mode', 'options': dict({ }), 'original_device_class': None, @@ -884,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power cool', 'options': dict({ }), 'original_device_class': None, @@ -932,6 +951,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -980,6 +1000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1028,6 +1049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto Cycle Link', 'options': dict({ }), 'original_device_class': None, @@ -1076,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keep fresh mode', 'options': dict({ }), 'original_device_class': None, @@ -1124,6 +1147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sanitize', 'options': dict({ }), 'original_device_class': None, @@ -1172,6 +1196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrinkle prevent', 'options': dict({ }), 'original_device_class': None, @@ -1220,6 +1245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrinkle prevent', 'options': dict({ }), 'original_device_class': None, @@ -1268,6 +1294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wrinkle prevent', 'options': dict({ }), 'original_device_class': None, @@ -1316,6 +1343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bubble Soak', 'options': dict({ }), 'original_device_class': None, @@ -1364,6 +1392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bubble Soak', 'options': dict({ }), 'original_device_class': None, @@ -1412,6 +1441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1460,6 +1490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1508,6 +1539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1556,6 +1588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1604,6 +1637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_update.ambr b/tests/components/smartthings/snapshots/test_update.ambr index eb6b99b3363..37890cb1165 100644 --- a/tests/components/smartthings/snapshots/test_update.ambr +++ b/tests/components/smartthings/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -203,6 +206,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -264,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -325,6 +330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -386,6 +392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -447,6 +454,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_vacuum.ambr b/tests/components/smartthings/snapshots/test_vacuum.ambr index 59bbae2b3e7..ded658e2808 100644 --- a/tests/components/smartthings/snapshots/test_vacuum.ambr +++ b/tests/components/smartthings/snapshots/test_vacuum.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smartthings/snapshots/test_valve.ambr b/tests/components/smartthings/snapshots/test_valve.ambr index 1e291d5913c..0757ea98bb3 100644 --- a/tests/components/smartthings/snapshots/test_valve.ambr +++ b/tests/components/smartthings/snapshots/test_valve.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smartthings/snapshots/test_water_heater.ambr b/tests/components/smartthings/snapshots/test_water_heater.ambr index d52400b9de2..671d1b81470 100644 --- a/tests/components/smartthings/snapshots/test_water_heater.ambr +++ b/tests/components/smartthings/snapshots/test_water_heater.ambr @@ -30,6 +30,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -103,6 +104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -176,6 +178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smarty/snapshots/test_binary_sensor.ambr b/tests/components/smarty/snapshots/test_binary_sensor.ambr index 935abfcfaaf..e2dff476ba3 100644 --- a/tests/components/smarty/snapshots/test_binary_sensor.ambr +++ b/tests/components/smarty/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boost state', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Warning', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smarty/snapshots/test_button.ambr b/tests/components/smarty/snapshots/test_button.ambr index 380fb2317c4..1d4a2756473 100644 --- a/tests/components/smarty/snapshots/test_button.ambr +++ b/tests/components/smarty/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filters timer', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smarty/snapshots/test_fan.ambr b/tests/components/smarty/snapshots/test_fan.ambr index a4f4f8989bd..493530571ff 100644 --- a/tests/components/smarty/snapshots/test_fan.ambr +++ b/tests/components/smarty/snapshots/test_fan.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smarty/snapshots/test_sensor.ambr b/tests/components/smarty/snapshots/test_sensor.ambr index 232cce177e3..4ff09f8375b 100644 --- a/tests/components/smarty/snapshots/test_sensor.ambr +++ b/tests/components/smarty/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extract air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extract fan speed', 'options': dict({ }), 'original_device_class': None, @@ -122,6 +124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter days left', 'options': dict({ }), 'original_device_class': , @@ -171,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -224,6 +228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply air temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -277,6 +282,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply fan speed', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smarty/snapshots/test_switch.ambr b/tests/components/smarty/snapshots/test_switch.ambr index b84cbf44be9..0ca67c04585 100644 --- a/tests/components/smarty/snapshots/test_switch.ambr +++ b/tests/components/smarty/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boost', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smhi/snapshots/test_sensor.ambr b/tests/components/smhi/snapshots/test_sensor.ambr index 17d9e2a959d..d1b64f1c569 100644 --- a/tests/components/smhi/snapshots/test_sensor.ambr +++ b/tests/components/smhi/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Build up index', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Drought code', 'options': dict({ }), 'original_device_class': None, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Duff moisture code', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fine fuel moisture code', 'options': dict({ }), 'original_device_class': None, @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fire weather index', 'options': dict({ }), 'original_device_class': None, @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frozen precipitation', 'options': dict({ }), 'original_device_class': None, @@ -339,6 +345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel drying', 'options': dict({ }), 'original_device_class': , @@ -406,6 +413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'FWI index', 'options': dict({ }), 'original_device_class': , @@ -464,6 +472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High cloud coverage', 'options': dict({ }), 'original_device_class': None, @@ -523,6 +532,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest grass fire risk', 'options': dict({ }), 'original_device_class': , @@ -583,6 +593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Initial spread index', 'options': dict({ }), 'original_device_class': None, @@ -633,6 +644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low cloud coverage', 'options': dict({ }), 'original_device_class': None, @@ -683,6 +695,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Medium cloud coverage', 'options': dict({ }), 'original_device_class': None, @@ -735,6 +748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Potential rate of spread', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -800,6 +814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation category', 'options': dict({ }), 'original_device_class': , @@ -859,6 +874,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Thunder probability', 'options': dict({ }), 'original_device_class': None, @@ -909,6 +925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cloud coverage', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/smlight/snapshots/test_binary_sensor.ambr b/tests/components/smlight/snapshots/test_binary_sensor.ambr index 570bc554313..22bab0ea6e1 100644 --- a/tests/components/smlight/snapshots/test_binary_sensor.ambr +++ b/tests/components/smlight/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ethernet', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Internet', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VPN', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smlight/snapshots/test_sensor.ambr b/tests/components/smlight/snapshots/test_sensor.ambr index d61872b024c..da5bb09f88c 100644 --- a/tests/components/smlight/snapshots/test_sensor.ambr +++ b/tests/components/smlight/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection mode', 'options': dict({ }), 'original_device_class': , @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core chip temp', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -136,6 +138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core uptime', 'options': dict({ }), 'original_device_class': , @@ -185,6 +188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filesystem usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -243,6 +247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware channel', 'options': dict({ }), 'original_device_class': , @@ -296,6 +301,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RAM usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -351,6 +357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zigbee chip temp', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -411,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zigbee type', 'options': dict({ }), 'original_device_class': , @@ -465,6 +473,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zigbee uptime', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smlight/snapshots/test_switch.ambr b/tests/components/smlight/snapshots/test_switch.ambr index 01bd9d99506..d979f248812 100644 --- a/tests/components/smlight/snapshots/test_switch.ambr +++ b/tests/components/smlight/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto Zigbee update', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disable LEDs', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED night mode', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VPN enabled', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/smlight/snapshots/test_update.ambr b/tests/components/smlight/snapshots/test_update.ambr index c1c04358ceb..a816f067459 100644 --- a/tests/components/smlight/snapshots/test_update.ambr +++ b/tests/components/smlight/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Core firmware', 'options': dict({ }), 'original_device_class': , @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zigbee firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/snapcast/snapshots/test_media_player.ambr b/tests/components/snapcast/snapshots/test_media_player.ambr index 3e408a0f14e..f4ea428707c 100644 --- a/tests/components/snapcast/snapshots/test_media_player.ambr +++ b/tests/components/snapcast/snapshots/test_media_player.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'test_client_1 Snapcast Client', 'options': dict({ }), 'original_device_class': , @@ -100,6 +101,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'test_client_2 Snapcast Client', 'options': dict({ }), 'original_device_class': , @@ -167,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test Group 1 Snapcast Group', 'options': dict({ }), 'original_device_class': , @@ -238,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test Group 2 Snapcast Group', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/snoo/snapshots/test_button.ambr b/tests/components/snoo/snapshots/test_button.ambr index 05920b09105..233de64a1a8 100644 --- a/tests/components/snoo/snapshots/test_button.ambr +++ b/tests/components/snoo/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/solarlog/snapshots/test_sensor.ambr b/tests/components/solarlog/snapshots/test_sensor.ambr index 0ddccf6a193..bbd9c761ae1 100644 --- a/tests/components/solarlog/snapshots/test_sensor.ambr +++ b/tests/components/solarlog/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -137,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -252,6 +256,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alternator loss', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -308,6 +313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -364,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge level', 'options': dict({ }), 'original_device_class': , @@ -417,6 +424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -473,6 +481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption AC', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -529,6 +538,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption day', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -588,6 +598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -647,6 +658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -706,6 +718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -763,6 +776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumption yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -821,6 +835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Discharging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -877,6 +892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Efficiency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -933,6 +949,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Installed peak power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -987,6 +1004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last update', 'options': dict({ }), 'original_device_class': , @@ -1038,6 +1056,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power AC', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1094,6 +1113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power available', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1150,6 +1170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power DC', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1206,6 +1227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Self-consumption year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1262,6 +1284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1318,6 +1341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage AC', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1374,6 +1398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage DC', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1430,6 +1455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yield day', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1489,6 +1515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yield month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1548,6 +1575,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yield total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1607,6 +1635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yield year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1664,6 +1693,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yield yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, diff --git a/tests/components/sonos/snapshots/test_media_player.ambr b/tests/components/sonos/snapshots/test_media_player.ambr index f47ba2f05da..4578d40f645 100644 --- a/tests/components/sonos/snapshots/test_media_player.ambr +++ b/tests/components/sonos/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/spotify/snapshots/test_media_player.ambr b/tests/components/spotify/snapshots/test_media_player.ambr index c275446d999..64c6d4ad916 100644 --- a/tests/components/spotify/snapshots/test_media_player.ambr +++ b/tests/components/spotify/snapshots/test_media_player.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -95,6 +96,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/squeezebox/snapshots/test_media_player.ambr b/tests/components/squeezebox/snapshots/test_media_player.ambr index 183b5ca767f..196f0dc95ab 100644 --- a/tests/components/squeezebox/snapshots/test_media_player.ambr +++ b/tests/components/squeezebox/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/squeezebox/snapshots/test_switch.ambr b/tests/components/squeezebox/snapshots/test_switch.ambr index 6d53eb38021..f58d866eee9 100644 --- a/tests/components/squeezebox/snapshots/test_switch.ambr +++ b/tests/components/squeezebox/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm (1)', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarms enabled', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/stookwijzer/snapshots/test_sensor.ambr b/tests/components/stookwijzer/snapshots/test_sensor.ambr index e0e3de207d0..7bdc134c9b0 100644 --- a/tests/components/stookwijzer/snapshots/test_sensor.ambr +++ b/tests/components/stookwijzer/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Advice code', 'options': dict({ }), 'original_device_class': , @@ -83,6 +84,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality index', 'options': dict({ }), 'original_device_class': , @@ -136,6 +138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/streamlabswater/snapshots/test_binary_sensor.ambr b/tests/components/streamlabswater/snapshots/test_binary_sensor.ambr index 38cbef26f6a..0c0ffd59036 100644 --- a/tests/components/streamlabswater/snapshots/test_binary_sensor.ambr +++ b/tests/components/streamlabswater/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Away mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/streamlabswater/snapshots/test_sensor.ambr b/tests/components/streamlabswater/snapshots/test_sensor.ambr index 404e636bd3e..06e75c49101 100644 --- a/tests/components/streamlabswater/snapshots/test_sensor.ambr +++ b/tests/components/streamlabswater/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monthly usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yearly usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/suez_water/snapshots/test_sensor.ambr b/tests/components/suez_water/snapshots/test_sensor.ambr index ed05348d924..55ef5f1472e 100644 --- a/tests/components/suez_water/snapshots/test_sensor.ambr +++ b/tests/components/suez_water/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water price', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water usage yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/sun/test_trigger.py b/tests/components/sun/test_trigger.py index ec848c61338..ae2bdbbdf23 100644 --- a/tests/components/sun/test_trigger.py +++ b/tests/components/sun/test_trigger.py @@ -21,11 +21,6 @@ from homeassistant.util import dt as dt_util from tests.common import async_fire_time_changed, mock_component -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) async def setup_comp(hass: HomeAssistant) -> None: """Initialize components.""" diff --git a/tests/components/sunricher_dali/conftest.py b/tests/components/sunricher_dali/conftest.py index 338e82f293b..f3f2ed489b2 100644 --- a/tests/components/sunricher_dali/conftest.py +++ b/tests/components/sunricher_dali/conftest.py @@ -63,6 +63,16 @@ DEVICE_DATA: list[dict[str, Any]] = [ }, ] +ILLUMINANCE_SENSOR_DATA: dict[str, Any] = { + "dev_id": "02020000206A242121110E", + "dev_type": "0202", + "name": "Illuminance Sensor 0000-20", + "model": "DALI Illuminance Sensor", + "color_mode": None, + "address": 20, + "channel": 0, +} + @pytest.fixture async def init_integration( @@ -126,6 +136,12 @@ def mock_devices() -> list[MagicMock]: return devices +@pytest.fixture +def mock_illuminance_device() -> MagicMock: + """Return a mocked illuminance sensor device.""" + return _create_mock_device(ILLUMINANCE_SENSOR_DATA) + + def _create_scene_device_property( dev_type: str, brightness: int = 128, **kwargs: Any ) -> dict[str, Any]: diff --git a/tests/components/sunricher_dali/snapshots/test_button.ambr b/tests/components/sunricher_dali/snapshots/test_button.ambr new file mode 100644 index 00000000000..f1ad8c12a42 --- /dev/null +++ b/tests/components/sunricher_dali/snapshots/test_button.ambr @@ -0,0 +1,201 @@ +# serializer version: 1 +# name: test_entities[button.cct_0000_03-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.cct_0000_03', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'sunricher_dali', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01020000036A242121110E_identify', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.cct_0000_03-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'CCT 0000-03', + }), + 'context': , + 'entity_id': 'button.cct_0000_03', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.dimmer_0000_02-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.dimmer_0000_02', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'sunricher_dali', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01010000026A242121110E_identify', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.dimmer_0000_02-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'Dimmer 0000-02', + }), + 'context': , + 'entity_id': 'button.dimmer_0000_02', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.hs_color_light-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.hs_color_light', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'sunricher_dali', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01030000046A242121110E_identify', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.hs_color_light-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'HS Color Light', + }), + 'context': , + 'entity_id': 'button.hs_color_light', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_entities[button.rgbw_light-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.rgbw_light', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'sunricher_dali', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '01040000056A242121110E_identify', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[button.rgbw_light-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'identify', + 'friendly_name': 'RGBW Light', + }), + 'context': , + 'entity_id': 'button.rgbw_light', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- diff --git a/tests/components/sunricher_dali/snapshots/test_light.ambr b/tests/components/sunricher_dali/snapshots/test_light.ambr index 0f95b2fc750..5c393547fb1 100644 --- a/tests/components/sunricher_dali/snapshots/test_light.ambr +++ b/tests/components/sunricher_dali/snapshots/test_light.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -95,6 +96,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -153,6 +155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -214,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sunricher_dali/snapshots/test_scene.ambr b/tests/components/sunricher_dali/snapshots/test_scene.ambr index c4812ef51b2..b373a5a6383 100644 --- a/tests/components/sunricher_dali/snapshots/test_scene.ambr +++ b/tests/components/sunricher_dali/snapshots/test_scene.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Kitchen Bright', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Living Room Evening', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/sunricher_dali/snapshots/test_sensor.ambr b/tests/components/sunricher_dali/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..fead384b976 --- /dev/null +++ b/tests/components/sunricher_dali/snapshots/test_sensor.ambr @@ -0,0 +1,55 @@ +# serializer version: 1 +# name: test_setup_entry[sensor.illuminance_sensor_0000_20-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.illuminance_sensor_0000_20', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'sunricher_dali', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '02020000206A242121110E', + 'unit_of_measurement': 'lx', + }) +# --- +# name: test_setup_entry[sensor.illuminance_sensor_0000_20-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'illuminance', + 'friendly_name': 'Illuminance Sensor 0000-20', + 'state_class': , + 'unit_of_measurement': 'lx', + }), + 'context': , + 'entity_id': 'sensor.illuminance_sensor_0000_20', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- diff --git a/tests/components/sunricher_dali/test_button.py b/tests/components/sunricher_dali/test_button.py new file mode 100644 index 00000000000..cd8fe64693c --- /dev/null +++ b/tests/components/sunricher_dali/test_button.py @@ -0,0 +1,46 @@ +"""Test the Sunricher DALI button platform.""" + +from unittest.mock import MagicMock + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS +from homeassistant.const import ATTR_ENTITY_ID, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.fixture +def platforms() -> list[Platform]: + """Fixture to specify which platforms to test.""" + return [Platform.BUTTON] + + +@pytest.mark.usefixtures("init_integration") +async def test_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test the button entities.""" + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +@pytest.mark.usefixtures("init_integration") +async def test_identify_button_press( + hass: HomeAssistant, + mock_devices: list[MagicMock], +) -> None: + """Test pressing the identify button calls device.identify().""" + await hass.services.async_call( + BUTTON_DOMAIN, + SERVICE_PRESS, + {ATTR_ENTITY_ID: "button.dimmer_0000_02"}, + blocking=True, + ) + + mock_devices[0].identify.assert_called_once() diff --git a/tests/components/sunricher_dali/test_sensor.py b/tests/components/sunricher_dali/test_sensor.py new file mode 100644 index 00000000000..0f6ba6aacba --- /dev/null +++ b/tests/components/sunricher_dali/test_sensor.py @@ -0,0 +1,131 @@ +"""Test the Sunricher DALI sensor platform.""" + +from unittest.mock import MagicMock + +from PySrDaliGateway import CallbackEventType +import pytest + +from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import find_device_listener, trigger_availability_callback + +from tests.common import MockConfigEntry, SnapshotAssertion, snapshot_platform + +ENTITY_ID = "sensor.illuminance_sensor_0000_20" + + +@pytest.fixture +def mock_devices(mock_illuminance_device: MagicMock) -> list[MagicMock]: + """Override mock_devices to use illuminance sensor only.""" + return [mock_illuminance_device] + + +@pytest.fixture +def platforms() -> list[Platform]: + """Fixture to specify which platforms to test.""" + return [Platform.SENSOR] + + +@pytest.mark.usefixtures("init_integration") +async def test_setup_entry( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, +) -> None: + """Test that async_setup_entry correctly creates sensor entities.""" + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + entity_entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + + assert len(entity_entries) == 1 + assert entity_entries[0].entity_id == ENTITY_ID + + +@pytest.mark.usefixtures("init_integration") +async def test_illuminance_callback( + hass: HomeAssistant, + mock_illuminance_device: MagicMock, +) -> None: + """Test IlluminanceSensor handles valid and invalid values correctly.""" + callback = find_device_listener( + mock_illuminance_device, CallbackEventType.ILLUMINANCE_STATUS + ) + + # Valid value should update state + callback({"illuminance_value": 500.0, "is_valid": True}) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert float(state.state) == 500.0 + + # Invalid value should be ignored + callback({"illuminance_value": 9999.0, "is_valid": False}) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert float(state.state) == 500.0 + + +@pytest.mark.usefixtures("init_integration") +async def test_sensor_on_off( + hass: HomeAssistant, + mock_illuminance_device: MagicMock, +) -> None: + """Test IlluminanceSensor handles sensor on/off callback correctly.""" + illuminance_callback = find_device_listener( + mock_illuminance_device, CallbackEventType.ILLUMINANCE_STATUS + ) + illuminance_callback({"illuminance_value": 250.0, "is_valid": True}) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert float(state.state) == 250.0 + + on_off_callback = find_device_listener( + mock_illuminance_device, CallbackEventType.SENSOR_ON_OFF + ) + + # Turn off sensor -> state becomes unknown + on_off_callback(False) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert state.state == STATE_UNKNOWN + + # Turn on sensor -> restore previous value + on_off_callback(True) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert float(state.state) == 250.0 + + +@pytest.mark.usefixtures("init_integration") +async def test_availability( + hass: HomeAssistant, + mock_illuminance_device: MagicMock, +) -> None: + """Test availability changes are reflected in sensor entity state.""" + trigger_availability_callback(mock_illuminance_device, False) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert state.state == STATE_UNAVAILABLE + + trigger_availability_callback(mock_illuminance_device, True) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state is not None + assert state.state != STATE_UNAVAILABLE diff --git a/tests/components/swiss_public_transport/snapshots/test_sensor.ambr b/tests/components/swiss_public_transport/snapshots/test_sensor.ambr index 1fbd2c17a6c..bc22cbac011 100644 --- a/tests/components/swiss_public_transport/snapshots/test_sensor.ambr +++ b/tests/components/swiss_public_transport/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delay', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure', 'options': dict({ }), 'original_device_class': , @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure +1', 'options': dict({ }), 'original_device_class': , @@ -174,6 +177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Departure +2', 'options': dict({ }), 'original_device_class': , @@ -224,6 +228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Line', 'options': dict({ }), 'original_device_class': None, @@ -273,6 +278,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Platform', 'options': dict({ }), 'original_device_class': None, @@ -322,6 +328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Transfers', 'options': dict({ }), 'original_device_class': None, @@ -371,6 +378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/switch/test_device_action.py b/tests/components/switch/test_device_action.py index 9751721cbc7..e8bcfa15c66 100644 --- a/tests/components/switch/test_device_action.py +++ b/tests/components/switch/test_device_action.py @@ -19,11 +19,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/switch/test_device_condition.py b/tests/components/switch/test_device_condition.py index 89c84b1ed34..ecdf6c04a5e 100644 --- a/tests/components/switch/test_device_condition.py +++ b/tests/components/switch/test_device_condition.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/switch/test_device_trigger.py b/tests/components/switch/test_device_trigger.py index a642bb44825..fdf73bc3cfe 100644 --- a/tests/components/switch/test_device_trigger.py +++ b/tests/components/switch/test_device_trigger.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/switch/test_trigger.py b/tests/components/switch/test_trigger.py index 4b679702e61..901a9e334d5 100644 --- a/tests/components/switch/test_trigger.py +++ b/tests/components/switch/test_trigger.py @@ -1,8 +1,6 @@ """Test switch triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, STATE_OFF, STATE_ from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -20,21 +18,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_switches(hass: HomeAssistant) -> list[str]: """Create multiple switch entities associated with different targets.""" @@ -61,7 +44,7 @@ async def test_switch_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -90,7 +73,7 @@ async def test_switch_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the switch state trigger fires when any switch state changes to a specific state.""" other_entity_ids = set(target_switches) - {entity_id} @@ -119,7 +102,7 @@ async def test_switch_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -148,7 +131,7 @@ async def test_switch_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the switch state trigger fires when the first switch changes to a specific state.""" other_entity_ids = set(target_switches) - {entity_id} @@ -176,7 +159,7 @@ async def test_switch_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -205,7 +188,7 @@ async def test_switch_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the switch state trigger fires when the last switch changes to a specific state.""" other_entity_ids = set(target_switches) - {entity_id} diff --git a/tests/components/switch_as_x/test_init.py b/tests/components/switch_as_x/test_init.py index a201cb258d6..4e69f37fedc 100644 --- a/tests/components/switch_as_x/test_init.py +++ b/tests/components/switch_as_x/test_init.py @@ -1146,8 +1146,8 @@ async def test_migrate( capabilities=CAPABILITY_MAP[target_domain], config_entry=config_entry, device_id=device_entry.id, + object_id_base="ABC", original_name="ABC", - suggested_object_id="abc", supported_features=SUPPORTED_FEATURE_MAP[target_domain], ) entity_registry.async_update_entity_options( diff --git a/tests/components/switchbot_cloud/snapshots/test_binary_sensor.ambr b/tests/components/switchbot_cloud/snapshots/test_binary_sensor.ambr index 0fb71d92195..a83d896f16b 100644 --- a/tests/components/switchbot_cloud/snapshots/test_binary_sensor.ambr +++ b/tests/components/switchbot_cloud/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opening', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Opening', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/switchbot_cloud/snapshots/test_fan.ambr b/tests/components/switchbot_cloud/snapshots/test_fan.ambr index e5139527aca..8367b134321 100644 --- a/tests/components/switchbot_cloud/snapshots/test_fan.ambr +++ b/tests/components/switchbot_cloud/snapshots/test_fan.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/switchbot_cloud/snapshots/test_humidifier.ambr b/tests/components/switchbot_cloud/snapshots/test_humidifier.ambr index d369b0f3b48..31199c50bf1 100644 --- a/tests/components/switchbot_cloud/snapshots/test_humidifier.ambr +++ b/tests/components/switchbot_cloud/snapshots/test_humidifier.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -99,6 +100,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/switchbot_cloud/snapshots/test_sensor.ambr b/tests/components/switchbot_cloud/snapshots/test_sensor.ambr index c5f7942dcd8..2dc5180f3a1 100644 --- a/tests/components/switchbot_cloud/snapshots/test_sensor.ambr +++ b/tests/components/switchbot_cloud/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -240,6 +244,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -299,6 +304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -355,6 +361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/syncthru/snapshots/test_binary_sensor.ambr b/tests/components/syncthru/snapshots/test_binary_sensor.ambr index 41be0698ad9..44625b69498 100644 --- a/tests/components/syncthru/snapshots/test_binary_sensor.ambr +++ b/tests/components/syncthru/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/syncthru/snapshots/test_sensor.ambr b/tests/components/syncthru/snapshots/test_sensor.ambr index 5d86fc41cc0..65f53a93cfd 100644 --- a/tests/components/syncthru/snapshots/test_sensor.ambr +++ b/tests/components/syncthru/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active alerts', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Black toner level', 'options': dict({ }), 'original_device_class': None, @@ -174,6 +177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cyan toner level', 'options': dict({ }), 'original_device_class': None, @@ -228,6 +232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input tray 1', 'options': dict({ }), 'original_device_class': None, @@ -285,6 +290,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Magenta toner level', 'options': dict({ }), 'original_device_class': None, @@ -339,6 +345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output tray 1', 'options': dict({ }), 'original_device_class': None, @@ -391,6 +398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yellow toner level', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/systemmonitor/test_sensor.py b/tests/components/systemmonitor/test_sensor.py index 10b7a853a91..be402c7e2b3 100644 --- a/tests/components/systemmonitor/test_sensor.py +++ b/tests/components/systemmonitor/test_sensor.py @@ -564,6 +564,7 @@ async def test_remove_obsolete_entities( has_entity_name=True, device_id=cpu_sensor_entity.device_id, translation_key="network_out", + suggested_object_id="systemmonitor_network_out_veth12345", ) # Fake an entity which should not be removed as not supported but not disabled entity_registry.async_get_or_create( @@ -575,6 +576,7 @@ async def test_remove_obsolete_entities( has_entity_name=True, device_id=cpu_sensor_entity.device_id, translation_key="network_out", + suggested_object_id="systemmonitor_network_out_veth54321", ) await hass.config_entries.async_reload(mock_added_config_entry.entry_id) await hass.async_block_till_done() diff --git a/tests/components/tado/snapshots/test_binary_sensor.ambr b/tests/components/tado/snapshots/test_binary_sensor.ambr index 5920e6bbf11..185f4467cd1 100644 --- a/tests/components/tado/snapshots/test_binary_sensor.ambr +++ b/tests/components/tado/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overlay', 'options': dict({ }), 'original_device_class': , @@ -119,6 +121,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -168,6 +171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window', 'options': dict({ }), 'original_device_class': , @@ -217,6 +221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -266,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overlay', 'options': dict({ }), 'original_device_class': , @@ -316,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -365,6 +372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window', 'options': dict({ }), 'original_device_class': , @@ -414,6 +422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -463,6 +472,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overlay', 'options': dict({ }), 'original_device_class': , @@ -512,6 +522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -561,6 +572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window', 'options': dict({ }), 'original_device_class': , @@ -610,6 +622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -659,6 +672,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Early start', 'options': dict({ }), 'original_device_class': , @@ -708,6 +722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overlay', 'options': dict({ }), 'original_device_class': , @@ -758,6 +773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -807,6 +823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window', 'options': dict({ }), 'original_device_class': , @@ -856,6 +873,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -905,6 +923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overlay', 'options': dict({ }), 'original_device_class': , @@ -955,6 +974,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1004,6 +1024,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connectivity', 'options': dict({ }), 'original_device_class': , @@ -1053,6 +1074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overlay', 'options': dict({ }), 'original_device_class': , @@ -1102,6 +1124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -1151,6 +1174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection state', 'options': dict({ }), 'original_device_class': , @@ -1200,6 +1224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Connection state', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tado/snapshots/test_climate.ambr b/tests/components/tado/snapshots/test_climate.ambr index fb1dd6d46d1..e17155eea3f 100644 --- a/tests/components/tado/snapshots/test_climate.ambr +++ b/tests/components/tado/snapshots/test_climate.ambr @@ -138,6 +138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -250,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -365,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -466,6 +469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tado/snapshots/test_sensor.ambr b/tests/components/tado/snapshots/test_sensor.ambr index 2040bd737c8..a4e94e31cf5 100644 --- a/tests/components/tado/snapshots/test_sensor.ambr +++ b/tests/components/tado/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, @@ -173,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -229,6 +233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC', 'options': dict({ }), 'original_device_class': None, @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -332,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, @@ -382,6 +389,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -438,6 +446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC', 'options': dict({ }), 'original_device_class': None, @@ -489,6 +498,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -541,6 +551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, @@ -591,6 +602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -649,6 +661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ }), 'original_device_class': None, @@ -702,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -754,6 +768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, @@ -804,6 +819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -860,6 +876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Automatic geofencing', 'options': dict({ }), 'original_device_class': None, @@ -908,6 +925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Geofencing mode', 'options': dict({ }), 'original_device_class': None, @@ -958,6 +976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1015,6 +1034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar percentage', 'options': dict({ }), 'original_device_class': None, @@ -1066,6 +1086,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, @@ -1114,6 +1135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather condition', 'options': dict({ }), 'original_device_class': None, @@ -1163,6 +1185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, @@ -1211,6 +1234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tado mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tado/snapshots/test_switch.ambr b/tests/components/tado/snapshots/test_switch.ambr index c2f00649f1d..4c53e065c23 100644 --- a/tests/components/tado/snapshots/test_switch.ambr +++ b/tests/components/tado/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tado/snapshots/test_water_heater.ambr b/tests/components/tado/snapshots/test_water_heater.ambr index 5e10af60c8d..127a944712b 100644 --- a/tests/components/tado/snapshots/test_water_heater.ambr +++ b/tests/components/tado/snapshots/test_water_heater.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tag/test_trigger.py b/tests/components/tag/test_trigger.py index 5c7e515d322..91f1bfba95b 100644 --- a/tests/components/tag/test_trigger.py +++ b/tests/components/tag/test_trigger.py @@ -12,11 +12,6 @@ from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.setup import async_setup_component -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture def tag_setup(hass: HomeAssistant, hass_storage: dict[str, Any]): """Tag setup.""" diff --git a/tests/components/tailwind/snapshots/test_binary_sensor.ambr b/tests/components/tailwind/snapshots/test_binary_sensor.ambr index 2cf93435bbf..592bfd74e9a 100644 --- a/tests/components/tailwind/snapshots/test_binary_sensor.ambr +++ b/tests/components/tailwind/snapshots/test_binary_sensor.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational problem', 'options': dict({ }), 'original_device_class': , @@ -114,6 +115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operational problem', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tailwind/snapshots/test_button.ambr b/tests/components/tailwind/snapshots/test_button.ambr index 12b99997db0..3c74dccb88b 100644 --- a/tests/components/tailwind/snapshots/test_button.ambr +++ b/tests/components/tailwind/snapshots/test_button.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identify', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tailwind/snapshots/test_cover.ambr b/tests/components/tailwind/snapshots/test_cover.ambr index a14dcfc44f1..58b56b25679 100644 --- a/tests/components/tailwind/snapshots/test_cover.ambr +++ b/tests/components/tailwind/snapshots/test_cover.ambr @@ -35,6 +35,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -116,6 +117,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tailwind/snapshots/test_number.ambr b/tests/components/tailwind/snapshots/test_number.ambr index f9132530cee..06580ef7168 100644 --- a/tests/components/tailwind/snapshots/test_number.ambr +++ b/tests/components/tailwind/snapshots/test_number.ambr @@ -43,6 +43,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status LED brightness', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tasmota/snapshots/test_sensor.ambr b/tests/components/tasmota/snapshots/test_sensor.ambr index 00b09239b26..34483828999 100644 --- a/tests/components/tasmota/snapshots/test_sensor.ambr +++ b/tests/components/tasmota/snapshots/test_sensor.ambr @@ -38,6 +38,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHT11 Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -122,6 +123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX23 Speed Act', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX23 Dir Card', 'options': dict({ }), 'original_device_class': None, @@ -277,6 +280,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY TotalTariff 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -429,6 +433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY TotalTariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -485,6 +490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY ExportTariff 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -541,6 +547,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY ExportTariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -629,6 +636,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DS18B20 Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -680,6 +688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DS18B20 Id', 'options': dict({ }), 'original_device_class': None, @@ -791,6 +800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY Total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -879,6 +889,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY Total 0', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -935,6 +946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY Total 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1055,6 +1067,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY Total Phase1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1111,6 +1124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ENERGY Total Phase2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1231,6 +1245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG Temperature1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1319,6 +1334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG Temperature2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1375,6 +1391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG Illuminance3', 'options': dict({ }), 'original_device_class': , @@ -1492,6 +1509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG CTEnergy1 Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1644,6 +1662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG CTEnergy1 Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1700,6 +1719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG CTEnergy1 Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1756,6 +1776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ANALOG CTEnergy1 Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1839,6 +1860,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SENSOR1 Unknown', 'options': dict({ }), 'original_device_class': None, @@ -1969,6 +1991,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SENSOR2 Unknown', 'options': dict({ }), 'original_device_class': None, @@ -2020,6 +2043,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SENSOR3 Unknown', 'options': dict({ }), 'original_device_class': None, @@ -2071,6 +2095,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SENSOR4 Unknown', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tasmota/test_device_trigger.py b/tests/components/tasmota/test_device_trigger.py index bb474358006..80138da69e8 100644 --- a/tests/components/tasmota/test_device_trigger.py +++ b/tests/components/tasmota/test_device_trigger.py @@ -23,11 +23,6 @@ from tests.common import async_fire_mqtt_message, async_get_device_automations from tests.typing import MqttMockHAClient, WebSocketGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers_btn( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/technove/snapshots/test_binary_sensor.ambr b/tests/components/technove/snapshots/test_binary_sensor.ambr index 7ab19670da4..54efd023db7 100644 --- a/tests/components/technove/snapshots/test_binary_sensor.ambr +++ b/tests/components/technove/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery protected', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Conflict with power sharing mode', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power sharing mode', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Static IP', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/technove/snapshots/test_number.ambr b/tests/components/technove/snapshots/test_number.ambr index 1be2d26ad44..a2f7b39fbf7 100644 --- a/tests/components/technove/snapshots/test_number.ambr +++ b/tests/components/technove/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum current', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/technove/snapshots/test_sensor.ambr b/tests/components/technove/snapshots/test_sensor.ambr index 801cc9fd38e..4720e4c5de6 100644 --- a/tests/components/technove/snapshots/test_sensor.ambr +++ b/tests/components/technove/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last session energy usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max station current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -361,6 +367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -419,6 +426,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -473,6 +481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi network name', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/technove/snapshots/test_switch.ambr b/tests/components/technove/snapshots/test_switch.ambr index f8e86db58b5..04311bafaa0 100644 --- a/tests/components/technove/snapshots/test_switch.ambr +++ b/tests/components/technove/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-charge', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging enabled', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tedee/snapshots/test_binary_sensor.ambr b/tests/components/tedee/snapshots/test_binary_sensor.ambr index dbde7932a6d..922cfb876a9 100644 --- a/tests/components/tedee/snapshots/test_binary_sensor.ambr +++ b/tests/components/tedee/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock uncalibrated', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pullspring enabled', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Semi locked', 'options': dict({ }), 'original_device_class': None, @@ -214,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock uncalibrated', 'options': dict({ }), 'original_device_class': , @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pullspring enabled', 'options': dict({ }), 'original_device_class': None, @@ -409,6 +417,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Semi locked', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tedee/snapshots/test_lock.ambr b/tests/components/tedee/snapshots/test_lock.ambr index a73e5c746aa..5938f7d14b9 100644 --- a/tests/components/tedee/snapshots/test_lock.ambr +++ b/tests/components/tedee/snapshots/test_lock.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -100,6 +101,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -149,6 +151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tedee/snapshots/test_sensor.ambr b/tests/components/tedee/snapshots/test_sensor.ambr index dd34c8bdac4..545a37d1ac9 100644 --- a/tests/components/tedee/snapshots/test_sensor.ambr +++ b/tests/components/tedee/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pullspring duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pullspring duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/template/conftest.py b/tests/components/template/conftest.py index cee25e50261..cb86c74830e 100644 --- a/tests/components/template/conftest.py +++ b/tests/components/template/conftest.py @@ -335,11 +335,6 @@ async def caplog_setup_text(caplog: pytest.LogCaptureFixture) -> str: return caplog.text -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def async_get_flow_preview_state( hass: HomeAssistant, hass_ws_client: WebSocketGenerator, diff --git a/tests/components/tesla_fleet/conftest.py b/tests/components/tesla_fleet/conftest.py index 10b01caca96..e3aece04d2f 100644 --- a/tests/components/tesla_fleet/conftest.py +++ b/tests/components/tesla_fleet/conftest.py @@ -35,7 +35,10 @@ def mock_expires_at() -> int: def create_config_entry( - expires_at: int, scopes: list[Scope], implementation: str = DOMAIN + expires_at: int, + scopes: list[Scope], + implementation: str = DOMAIN, + region: str = "NA", ) -> MockConfigEntry: """Create Tesla Fleet entry in Home Assistant.""" access_token = jwt.encode( @@ -43,7 +46,7 @@ def create_config_entry( "sub": UID, "aud": [], "scp": scopes, - "ou_code": "NA", + "ou_code": region, }, key="", algorithm="none", diff --git a/tests/components/tesla_fleet/snapshots/test_binary_sensor.ambr b/tests/components/tesla_fleet/snapshots/test_binary_sensor.ambr index 96de02d77d6..9446b692389 100644 --- a/tests/components/tesla_fleet/snapshots/test_binary_sensor.ambr +++ b/tests/components/tesla_fleet/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup capable', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services active', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services enabled', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storm watch active', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery heater', 'options': dict({ }), 'original_device_class': , @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection actively cooling', 'options': dict({ }), 'original_device_class': , @@ -310,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable', 'options': dict({ }), 'original_device_class': , @@ -359,6 +366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger has multiple phases', 'options': dict({ }), 'original_device_class': None, @@ -407,6 +415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dashcam', 'options': dict({ }), 'original_device_class': , @@ -456,6 +465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front driver door', 'options': dict({ }), 'original_device_class': , @@ -505,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front driver window', 'options': dict({ }), 'original_device_class': , @@ -554,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front passenger door', 'options': dict({ }), 'original_device_class': , @@ -603,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front passenger window', 'options': dict({ }), 'original_device_class': , @@ -652,6 +665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preconditioning', 'options': dict({ }), 'original_device_class': None, @@ -700,6 +714,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preconditioning enabled', 'options': dict({ }), 'original_device_class': None, @@ -748,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear driver door', 'options': dict({ }), 'original_device_class': , @@ -797,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear driver window', 'options': dict({ }), 'original_device_class': , @@ -846,6 +863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear passenger door', 'options': dict({ }), 'original_device_class': , @@ -895,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear passenger window', 'options': dict({ }), 'original_device_class': , @@ -944,6 +963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scheduled charging pending', 'options': dict({ }), 'original_device_class': None, @@ -992,6 +1012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -1041,6 +1062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning front left', 'options': dict({ }), 'original_device_class': , @@ -1090,6 +1112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning front right', 'options': dict({ }), 'original_device_class': , @@ -1139,6 +1162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning rear left', 'options': dict({ }), 'original_device_class': , @@ -1188,6 +1212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning rear right', 'options': dict({ }), 'original_device_class': , @@ -1237,6 +1262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip charging', 'options': dict({ }), 'original_device_class': None, @@ -1285,6 +1311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User present', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tesla_fleet/snapshots/test_button.ambr b/tests/components/tesla_fleet/snapshots/test_button.ambr index bb0e120a96f..cc7eed1f315 100644 --- a/tests/components/tesla_fleet/snapshots/test_button.ambr +++ b/tests/components/tesla_fleet/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Homelink', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk horn', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keyless driving', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Play fart', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wake', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/snapshots/test_climate.ambr b/tests/components/tesla_fleet/snapshots/test_climate.ambr index 0f1a2beb113..31fb10b2a28 100644 --- a/tests/components/tesla_fleet/snapshots/test_climate.ambr +++ b/tests/components/tesla_fleet/snapshots/test_climate.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': None, @@ -101,6 +102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, @@ -174,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': None, @@ -245,6 +248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, @@ -318,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': None, @@ -389,6 +394,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/snapshots/test_cover.ambr b/tests/components/tesla_fleet/snapshots/test_cover.ambr index a721e899a26..6055a17046e 100644 --- a/tests/components/tesla_fleet/snapshots/test_cover.ambr +++ b/tests/components/tesla_fleet/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -420,6 +428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -470,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -520,6 +530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -570,6 +581,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -620,6 +632,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -670,6 +683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -720,6 +734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tesla_fleet/snapshots/test_device_tracker.ambr b/tests/components/tesla_fleet/snapshots/test_device_tracker.ambr index 879c50b15bb..c550f9ef8ed 100644 --- a/tests/components/tesla_fleet/snapshots/test_device_tracker.ambr +++ b/tests/components/tesla_fleet/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/snapshots/test_lock.ambr b/tests/components/tesla_fleet/snapshots/test_lock.ambr index 4c7c85fd2e5..6034b42bcc9 100644 --- a/tests/components/tesla_fleet/snapshots/test_lock.ambr +++ b/tests/components/tesla_fleet/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable lock', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/snapshots/test_media_player.ambr b/tests/components/tesla_fleet/snapshots/test_media_player.ambr index ccd39ff33ac..82251015a7e 100644 --- a/tests/components/tesla_fleet/snapshots/test_media_player.ambr +++ b/tests/components/tesla_fleet/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Media player', 'options': dict({ }), 'original_device_class': , @@ -101,6 +102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Media player', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tesla_fleet/snapshots/test_number.ambr b/tests/components/tesla_fleet/snapshots/test_number.ambr index 926c2f23ce8..cde92c34715 100644 --- a/tests/components/tesla_fleet/snapshots/test_number.ambr +++ b/tests/components/tesla_fleet/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup reserve', 'options': dict({ }), 'original_device_class': , @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-grid reserve', 'options': dict({ }), 'original_device_class': , @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge current', 'options': dict({ }), 'original_device_class': , @@ -204,6 +207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge limit', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tesla_fleet/snapshots/test_select.ambr b/tests/components/tesla_fleet/snapshots/test_select.ambr index 7e698a088be..6c4c650f275 100644 --- a/tests/components/tesla_fleet/snapshots/test_select.ambr +++ b/tests/components/tesla_fleet/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow export', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operation mode', 'options': dict({ }), 'original_device_class': None, @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater front left', 'options': dict({ }), 'original_device_class': None, @@ -206,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater front right', 'options': dict({ }), 'original_device_class': None, @@ -267,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear center', 'options': dict({ }), 'original_device_class': None, @@ -328,6 +333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear left', 'options': dict({ }), 'original_device_class': None, @@ -389,6 +395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear right', 'options': dict({ }), 'original_device_class': None, @@ -450,6 +457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater third row left', 'options': dict({ }), 'original_device_class': None, @@ -511,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater third row right', 'options': dict({ }), 'original_device_class': None, @@ -571,6 +580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steering wheel heater', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/snapshots/test_sensor.ambr b/tests/components/tesla_fleet/snapshots/test_sensor.ambr index 8db495adfab..4680835c693 100644 --- a/tests/components/tesla_fleet/snapshots/test_sensor.ambr +++ b/tests/components/tesla_fleet/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -172,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -247,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery imported from generator', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -322,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery imported from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -397,6 +402,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery imported from solar', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -472,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -547,6 +554,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -622,6 +630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from generator', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -697,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -772,6 +782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from solar', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -847,6 +858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -922,6 +934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -997,6 +1010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1072,6 +1086,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1147,6 +1162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported from battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1222,6 +1238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported from generator', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1297,6 +1314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported from solar', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1372,6 +1390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid imported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1447,6 +1466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1522,6 +1542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1597,6 +1618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services imported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1672,6 +1694,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1753,6 +1776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid status', 'options': dict({ }), 'original_device_class': , @@ -1832,6 +1856,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Home usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1907,6 +1932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1982,6 +2008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Percentage charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2054,6 +2081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2129,6 +2157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar generated', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2204,6 +2233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2279,6 +2309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total pack energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2352,6 +2383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Version', 'options': dict({ }), 'original_device_class': None, @@ -2413,6 +2445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VPP backup reserve', 'options': dict({ }), 'original_device_class': , @@ -2480,6 +2513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery level', 'options': dict({ }), 'original_device_class': , @@ -2549,6 +2583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2622,6 +2657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable', 'options': dict({ }), 'original_device_class': None, @@ -2685,6 +2721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge energy added', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2757,6 +2794,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2832,6 +2870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2904,6 +2943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2976,6 +3016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3055,6 +3096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -3136,6 +3178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to arrival', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3211,6 +3254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Driver temperature setting', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3283,6 +3327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimate battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3356,6 +3401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fast charger type', 'options': dict({ }), 'original_device_class': None, @@ -3419,6 +3465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ideal battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3494,6 +3541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3566,6 +3614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3641,6 +3690,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3713,6 +3763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Passenger temperature setting', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3785,6 +3836,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3862,6 +3914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Shift state', 'options': dict({ }), 'original_device_class': , @@ -3939,6 +3992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4014,6 +4068,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge at arrival', 'options': dict({ }), 'original_device_class': , @@ -4081,6 +4136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to arrival', 'options': dict({ }), 'original_device_class': , @@ -4144,6 +4200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to full charge', 'options': dict({ }), 'original_device_class': , @@ -4209,6 +4266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure front left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4284,6 +4342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure front right', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4359,6 +4418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure rear left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4434,6 +4494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure rear right', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4509,6 +4570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Traffic delay', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4581,6 +4643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Usable battery level', 'options': dict({ }), 'original_device_class': , @@ -4648,6 +4711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault state code', 'options': dict({ }), 'original_device_class': None, @@ -4709,6 +4773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault state code', 'options': dict({ }), 'original_device_class': None, @@ -4772,6 +4837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4847,6 +4913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4920,6 +4987,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State code', 'options': dict({ }), 'original_device_class': None, @@ -4981,6 +5049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State code', 'options': dict({ }), 'original_device_class': None, @@ -5042,6 +5111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, @@ -5103,6 +5173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/snapshots/test_switch.ambr b/tests/components/tesla_fleet/snapshots/test_switch.ambr index b9efff6f23b..a07b28038fa 100644 --- a/tests/components/tesla_fleet/snapshots/test_switch.ambr +++ b/tests/components/tesla_fleet/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow charging from grid', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storm watch', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto seat climate left', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto seat climate right', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto steering wheel heater', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrost', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sentry mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tesla_fleet/snapshots/test_update.ambr b/tests/components/tesla_fleet/snapshots/test_update.ambr index 445305220d0..5a697434fa4 100644 --- a/tests/components/tesla_fleet/snapshots/test_update.ambr +++ b/tests/components/tesla_fleet/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': None, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tesla_fleet/test_init.py b/tests/components/tesla_fleet/test_init.py index eabb00aafbd..8fca02cba65 100644 --- a/tests/components/tesla_fleet/test_init.py +++ b/tests/components/tesla_fleet/test_init.py @@ -230,6 +230,52 @@ async def test_vehicle_refresh_ratelimited( assert state.state == "unknown" +async def test_vehicle_refresh_ratelimited_no_after( + hass: HomeAssistant, + normal_config_entry: MockConfigEntry, + mock_vehicle_data: AsyncMock, + freezer: FrozenDateTimeFactory, +) -> None: + """Test coordinator refresh handles 429 without after.""" + + await setup_platform(hass, normal_config_entry) + # mock_vehicle_data called once during setup + assert mock_vehicle_data.call_count == 1 + + mock_vehicle_data.side_effect = RateLimited({}) + freezer.tick(VEHICLE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # Called again during refresh, failed with RateLimited + assert mock_vehicle_data.call_count == 2 + + freezer.tick(VEHICLE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # Called again because skip refresh doesn't change interval + assert mock_vehicle_data.call_count == 3 + + +async def test_init_invalid_region( + hass: HomeAssistant, + expires_at: int, +) -> None: + """Test init with an invalid region in the token.""" + + # ou_code 'other' should be caught by the region validation and set to None + config_entry = create_config_entry( + expires_at, [Scope.VEHICLE_DEVICE_DATA], region="other" + ) + + with patch("homeassistant.components.tesla_fleet.TeslaFleetApi") as mock_api: + await setup_platform(hass, config_entry) + # Check if TeslaFleetApi was called with region=None + mock_api.assert_called() + assert mock_api.call_args.kwargs.get("region") is None + + async def test_vehicle_sleep( hass: HomeAssistant, normal_config_entry: MockConfigEntry, diff --git a/tests/components/tesla_fleet/test_number.py b/tests/components/tesla_fleet/test_number.py index 66734c27f6f..d9148464a7b 100644 --- a/tests/components/tesla_fleet/test_number.py +++ b/tests/components/tesla_fleet/test_number.py @@ -85,6 +85,21 @@ async def test_number_services( assert state.state == "60" call.assert_called_once() + # Test float conversion + with patch( + "tesla_fleet_api.tesla.VehicleFleet.set_charge_limit", + return_value=COMMAND_OK, + ) as call: + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + {ATTR_ENTITY_ID: entity_id, ATTR_VALUE: 60.5}, + blocking=True, + ) + state = hass.states.get(entity_id) + assert state.state == "60" + call.assert_called_once_with(60) + entity_id = "number.energy_site_backup_reserve" with patch( "tesla_fleet_api.tesla.EnergySite.backup", diff --git a/tests/components/teslemetry/conftest.py b/tests/components/teslemetry/conftest.py index 0d0e7d583cf..09bee83ca9e 100644 --- a/tests/components/teslemetry/conftest.py +++ b/tests/components/teslemetry/conftest.py @@ -4,11 +4,14 @@ from __future__ import annotations from collections.abc import Generator from copy import deepcopy +from typing import Any from unittest.mock import AsyncMock, patch import pytest from teslemetry_stream.stream import recursive_match +from homeassistant.components.teslemetry.const import TOKEN_URL + from .const import ( COMMAND_OK, ENERGY_HISTORY, @@ -21,6 +24,8 @@ from .const import ( WAKE_UP_ONLINE, ) +from tests.test_util.aiohttp import AiohttpClientMocker + @pytest.fixture def mock_setup_entry(): @@ -31,6 +36,25 @@ def mock_setup_entry(): yield mock_async_setup_entry +@pytest.fixture +def mock_token_response() -> dict[str, Any]: + """Return a mock OAuth token response.""" + return { + "refresh_token": "mock-refresh-token", + "access_token": "mock-access-token", + "type": "Bearer", + "expires_in": 60, + } + + +@pytest.fixture +def mock_token_post( + aioclient_mock: AiohttpClientMocker, mock_token_response: dict[str, Any] +) -> None: + """Mock the OAuth token endpoint.""" + aioclient_mock.post(TOKEN_URL, json=mock_token_response) + + @pytest.fixture(autouse=True) def mock_metadata(): """Mock Tesla Fleet Api metadata method.""" diff --git a/tests/components/teslemetry/snapshots/test_binary_sensor.ambr b/tests/components/teslemetry/snapshots/test_binary_sensor.ambr index 2b920a0cfdc..8ac20856f49 100644 --- a/tests/components/teslemetry/snapshots/test_binary_sensor.ambr +++ b/tests/components/teslemetry/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup capable', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services active', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services enabled', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid status', 'options': dict({ }), 'original_device_class': , @@ -213,6 +217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storm watch active', 'options': dict({ }), 'original_device_class': None, @@ -261,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery heater', 'options': dict({ }), 'original_device_class': , @@ -310,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection active', 'options': dict({ }), 'original_device_class': , @@ -359,6 +366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable', 'options': dict({ }), 'original_device_class': , @@ -408,6 +416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger has multiple phases', 'options': dict({ }), 'original_device_class': None, @@ -456,6 +465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dashcam', 'options': dict({ }), 'original_device_class': , @@ -505,6 +515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front driver door', 'options': dict({ }), 'original_device_class': , @@ -554,6 +565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front driver window', 'options': dict({ }), 'original_device_class': , @@ -603,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front passenger door', 'options': dict({ }), 'original_device_class': , @@ -652,6 +665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front passenger window', 'options': dict({ }), 'original_device_class': , @@ -701,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preconditioning', 'options': dict({ }), 'original_device_class': None, @@ -749,6 +764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preconditioning enabled', 'options': dict({ }), 'original_device_class': None, @@ -797,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear driver door', 'options': dict({ }), 'original_device_class': , @@ -846,6 +863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear driver window', 'options': dict({ }), 'original_device_class': , @@ -895,6 +913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear passenger door', 'options': dict({ }), 'original_device_class': , @@ -944,6 +963,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear passenger window', 'options': dict({ }), 'original_device_class': , @@ -993,6 +1013,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scheduled charging pending', 'options': dict({ }), 'original_device_class': None, @@ -1041,6 +1062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -1090,6 +1112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning front left', 'options': dict({ }), 'original_device_class': , @@ -1139,6 +1162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning front right', 'options': dict({ }), 'original_device_class': , @@ -1188,6 +1212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning rear left', 'options': dict({ }), 'original_device_class': , @@ -1237,6 +1262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning rear right', 'options': dict({ }), 'original_device_class': , @@ -1286,6 +1312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip charging', 'options': dict({ }), 'original_device_class': None, @@ -1334,6 +1361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User present', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/teslemetry/snapshots/test_button.ambr b/tests/components/teslemetry/snapshots/test_button.ambr index 714d4ed1f6d..d62ad518b03 100644 --- a/tests/components/teslemetry/snapshots/test_button.ambr +++ b/tests/components/teslemetry/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Homelink', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk horn', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keyless driving', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Play fart', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wake', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/snapshots/test_climate.ambr b/tests/components/teslemetry/snapshots/test_climate.ambr index 11708be7e39..f9c561a0df8 100644 --- a/tests/components/teslemetry/snapshots/test_climate.ambr +++ b/tests/components/teslemetry/snapshots/test_climate.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': None, @@ -105,6 +106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, @@ -183,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': None, @@ -258,6 +261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, @@ -336,6 +340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': None, @@ -378,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/snapshots/test_cover.ambr b/tests/components/teslemetry/snapshots/test_cover.ambr index cec35e79fc7..8f76ce8a943 100644 --- a/tests/components/teslemetry/snapshots/test_cover.ambr +++ b/tests/components/teslemetry/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -420,6 +428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , @@ -470,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -520,6 +530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -570,6 +581,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -620,6 +632,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -670,6 +683,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Windows', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/teslemetry/snapshots/test_device_tracker.ambr b/tests/components/teslemetry/snapshots/test_device_tracker.ambr index c71f818479a..f4fc65e208d 100644 --- a/tests/components/teslemetry/snapshots/test_device_tracker.ambr +++ b/tests/components/teslemetry/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/snapshots/test_lock.ambr b/tests/components/teslemetry/snapshots/test_lock.ambr index e84c00e46de..6bf41c256c3 100644 --- a/tests/components/teslemetry/snapshots/test_lock.ambr +++ b/tests/components/teslemetry/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable lock', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable lock', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/snapshots/test_media_player.ambr b/tests/components/teslemetry/snapshots/test_media_player.ambr index 75f482700cc..7c3b372c429 100644 --- a/tests/components/teslemetry/snapshots/test_media_player.ambr +++ b/tests/components/teslemetry/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Media player', 'options': dict({ }), 'original_device_class': , @@ -102,6 +103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Media player', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/teslemetry/snapshots/test_number.ambr b/tests/components/teslemetry/snapshots/test_number.ambr index 70d7bfd33a9..23852aee5a6 100644 --- a/tests/components/teslemetry/snapshots/test_number.ambr +++ b/tests/components/teslemetry/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup reserve', 'options': dict({ }), 'original_device_class': , @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-grid reserve', 'options': dict({ }), 'original_device_class': , @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge current', 'options': dict({ }), 'original_device_class': , @@ -204,6 +207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge limit', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/teslemetry/snapshots/test_select.ambr b/tests/components/teslemetry/snapshots/test_select.ambr index 08b70a22569..50e82467110 100644 --- a/tests/components/teslemetry/snapshots/test_select.ambr +++ b/tests/components/teslemetry/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow export', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operation mode', 'options': dict({ }), 'original_device_class': None, @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater front left', 'options': dict({ }), 'original_device_class': None, @@ -206,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater front right', 'options': dict({ }), 'original_device_class': None, @@ -267,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear center', 'options': dict({ }), 'original_device_class': None, @@ -328,6 +333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear left', 'options': dict({ }), 'original_device_class': None, @@ -389,6 +395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear right', 'options': dict({ }), 'original_device_class': None, @@ -449,6 +456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steering wheel heater', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/snapshots/test_sensor.ambr b/tests/components/teslemetry/snapshots/test_sensor.ambr index 1db8cf9612f..b6f0d8554f7 100644 --- a/tests/components/teslemetry/snapshots/test_sensor.ambr +++ b/tests/components/teslemetry/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery discharged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -172,6 +174,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -247,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery imported from generator', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -322,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery imported from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -397,6 +402,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery imported from solar', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -472,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -547,6 +554,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -622,6 +630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from generator', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -697,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from grid', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -772,6 +782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumer imported from solar', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -847,6 +858,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -922,6 +934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -997,6 +1010,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1072,6 +1086,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1147,6 +1162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported from battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1222,6 +1238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported from generator', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1297,6 +1314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid exported from solar', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1372,6 +1390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid imported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1447,6 +1466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1522,6 +1542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1597,6 +1618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services imported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1672,6 +1694,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1747,6 +1770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Home usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1828,6 +1852,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Island status', 'options': dict({ }), 'original_device_class': , @@ -1907,6 +1932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1982,6 +2008,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Percentage charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2054,6 +2081,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar exported', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2129,6 +2157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar generated', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2204,6 +2233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2279,6 +2309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total pack energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2352,6 +2383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Version', 'options': dict({ }), 'original_device_class': None, @@ -2413,6 +2445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VPP backup reserve', 'options': dict({ }), 'original_device_class': , @@ -2480,6 +2513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Teslemetry credits', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2550,6 +2584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2622,6 +2657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2695,6 +2731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable', 'options': dict({ }), 'original_device_class': None, @@ -2758,6 +2795,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge energy added', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2830,6 +2868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2905,6 +2944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2977,6 +3017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3049,6 +3090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3128,6 +3170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -3209,6 +3252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to arrival', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3284,6 +3328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Driver temperature setting', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3356,6 +3401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimate battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3429,6 +3475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fast charger type', 'options': dict({ }), 'original_device_class': None, @@ -3492,6 +3539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ideal battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3567,6 +3615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3639,6 +3688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3714,6 +3764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3786,6 +3837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Passenger temperature setting', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3858,6 +3910,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3935,6 +3988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Shift state', 'options': dict({ }), 'original_device_class': , @@ -4012,6 +4066,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4087,6 +4142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge at arrival', 'options': dict({ }), 'original_device_class': , @@ -4154,6 +4210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to arrival', 'options': dict({ }), 'original_device_class': , @@ -4217,6 +4274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to full charge', 'options': dict({ }), 'original_device_class': , @@ -4282,6 +4340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure front left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4357,6 +4416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure front right', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4432,6 +4492,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure rear left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4507,6 +4568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure rear right', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4582,6 +4644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Traffic delay', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4654,6 +4717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Usable battery level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4724,6 +4788,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault state code', 'options': dict({ }), 'original_device_class': None, @@ -4785,6 +4850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fault state code', 'options': dict({ }), 'original_device_class': None, @@ -4848,6 +4914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4923,6 +4990,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4996,6 +5064,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State code', 'options': dict({ }), 'original_device_class': None, @@ -5057,6 +5126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State code', 'options': dict({ }), 'original_device_class': None, @@ -5118,6 +5188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, @@ -5179,6 +5250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/snapshots/test_switch.ambr b/tests/components/teslemetry/snapshots/test_switch.ambr index bbcadd25a48..326b5fa2c65 100644 --- a/tests/components/teslemetry/snapshots/test_switch.ambr +++ b/tests/components/teslemetry/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow charging from grid', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storm watch', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto seat climate left', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto seat climate right', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto steering wheel heater', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrost', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sentry mode', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valet mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/teslemetry/snapshots/test_update.ambr b/tests/components/teslemetry/snapshots/test_update.ambr index 6f939c667b2..54fa3a05c70 100644 --- a/tests/components/teslemetry/snapshots/test_update.ambr +++ b/tests/components/teslemetry/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': None, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/teslemetry/test_config_flow.py b/tests/components/teslemetry/test_config_flow.py index 7659c0ab6bc..cef4e10d9ff 100644 --- a/tests/components/teslemetry/test_config_flow.py +++ b/tests/components/teslemetry/test_config_flow.py @@ -1,6 +1,7 @@ """Test the Teslemetry config flow.""" import time +from typing import Any from unittest.mock import AsyncMock, patch from urllib.parse import parse_qs, urlparse @@ -302,6 +303,213 @@ async def test_oauth_error_handling( assert result["reason"] == "oauth_error" +@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("mock_setup_entry") +async def test_reconfigure( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_token_response: dict[str, Any], +) -> None: + """Test reconfigure flow.""" + mock_entry = await setup_platform(hass, []) + client = await hass_client_no_auth() + + result = await mock_entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.EXTERNAL_STEP + + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": REDIRECT, + }, + ) + await client.get(f"/auth/external/callback?code=abcd&state={state}") + + new_token_response = mock_token_response | { + "refresh_token": "new_refresh_token", + "access_token": "new_access_token", + } + aioclient_mock.post(TOKEN_URL, json=new_token_response) + + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + + # Verify entry data was updated + assert mock_entry.data["auth_implementation"] == DOMAIN + assert mock_entry.data["token"]["refresh_token"] == "new_refresh_token" + assert mock_entry.data["token"]["access_token"] == "new_access_token" + assert mock_entry.data["token"]["type"] == "Bearer" + assert mock_entry.data["token"]["expires_in"] == 60 + assert "expires_at" in mock_entry.data["token"] + + +@pytest.mark.usefixtures("current_request_with_host") +async def test_reconfigure_account_mismatch( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_token_response: dict[str, Any], +) -> None: + """Test reconfigure with different account.""" + # Create an entry with a different unique_id to test account mismatch + old_entry = MockConfigEntry( + domain=DOMAIN, + version=2, + unique_id="baduid", + data={ + "auth_implementation": DOMAIN, + "token": { + "access_token": "old_access_token", + "refresh_token": "old_refresh_token", + "expires_at": int(time.time()) + 3600, + }, + }, + ) + old_entry.add_to_hass(hass) + + # Setup the integration properly to import client credentials + with patch( + "homeassistant.components.teslemetry.async_setup_entry", return_value=True + ): + await hass.config_entries.async_setup(old_entry.entry_id) + await hass.async_block_till_done() + + client = await hass_client_no_auth() + result = await old_entry.start_reconfigure_flow(hass) + + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": REDIRECT, + }, + ) + await client.get(f"/auth/external/callback?code=abcd&state={state}") + aioclient_mock.post(TOKEN_URL, json=mock_token_response) + + with patch( + "homeassistant.components.teslemetry.async_setup_entry", return_value=True + ): + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_account_mismatch" + + +@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.parametrize( + "exception", + [ + InvalidToken, + SubscriptionRequired, + ClientConnectionError, + TeslaFleetError("API error"), + ], +) +async def test_reconfigure_oauth_error_handling( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_token_response: dict[str, Any], + exception: Exception, +) -> None: + """Test reconfigure flow with various API errors.""" + mock_entry = await setup_platform(hass, []) + client = await hass_client_no_auth() + + result = await mock_entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.EXTERNAL_STEP + + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": REDIRECT, + }, + ) + await client.get(f"/auth/external/callback?code=abcd&state={state}") + aioclient_mock.post(TOKEN_URL, json=mock_token_response) + + with patch( + "tesla_fleet_api.teslemetry.Teslemetry.metadata", + side_effect=exception, + ): + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "oauth_error" + + +@pytest.mark.usefixtures("current_request_with_host") +@pytest.mark.usefixtures("mock_setup_entry") +async def test_reconfigure_oauth_error_recovery( + hass: HomeAssistant, + hass_client_no_auth: ClientSessionGenerator, + aioclient_mock: AiohttpClientMocker, + mock_token_response: dict[str, Any], +) -> None: + """Test reconfigure flow can recover from an OAuth error.""" + mock_entry = await setup_platform(hass, []) + client = await hass_client_no_auth() + + # First attempt - simulate OAuth error + result = await mock_entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.EXTERNAL_STEP + + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": REDIRECT, + }, + ) + await client.get(f"/auth/external/callback?code=abcd&state={state}") + aioclient_mock.post(TOKEN_URL, json=mock_token_response) + + with patch( + "tesla_fleet_api.teslemetry.Teslemetry.metadata", + side_effect=ClientConnectionError, + ): + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "oauth_error" + + # Second attempt - should succeed (recovery) + result = await mock_entry.start_reconfigure_flow(hass) + assert result["type"] is FlowResultType.EXTERNAL_STEP + + state = config_entry_oauth2_flow._encode_jwt( + hass, + { + "flow_id": result["flow_id"], + "redirect_uri": REDIRECT, + }, + ) + await client.get(f"/auth/external/callback?code=abcd&state={state}") + + aioclient_mock.clear_requests() + new_token_response = mock_token_response | { + "refresh_token": "new_refresh_token", + "access_token": "new_access_token", + } + aioclient_mock.post(TOKEN_URL, json=new_token_response) + + result = await hass.config_entries.flow.async_configure(result["flow_id"]) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + + # Verify entry data was updated after recovery + assert mock_entry.data["token"]["refresh_token"] == "new_refresh_token" + assert mock_entry.data["token"]["access_token"] == "new_access_token" + + async def test_migrate_error_from_future( hass: HomeAssistant, mock_metadata: AsyncMock ) -> None: diff --git a/tests/components/teslemetry/test_init.py b/tests/components/teslemetry/test_init.py index 9f0415459fd..bb6ca8a4ed2 100644 --- a/tests/components/teslemetry/test_init.py +++ b/tests/components/teslemetry/test_init.py @@ -1,5 +1,6 @@ """Test the Teslemetry init.""" +from copy import deepcopy import time from unittest.mock import AsyncMock, MagicMock, patch @@ -8,17 +9,24 @@ from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion from tesla_fleet_api.exceptions import ( + InvalidResponse, InvalidToken, + RateLimited, SubscriptionRequired, TeslaFleetError, ) from homeassistant.components.teslemetry.const import CLIENT_ID, DOMAIN -from homeassistant.components.teslemetry.coordinator import VEHICLE_INTERVAL + +# Coordinator constants +from homeassistant.components.teslemetry.coordinator import ( + ENERGY_HISTORY_INTERVAL, + ENERGY_LIVE_INTERVAL, + VEHICLE_INTERVAL, +) from homeassistant.components.teslemetry.models import TeslemetryData from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ( - CONF_ACCESS_TOKEN, STATE_OFF, STATE_ON, STATE_UNAVAILABLE, @@ -29,9 +37,16 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from . import setup_platform -from .const import CONFIG_V1, PRODUCTS_MODERN, UNIQUE_ID, VEHICLE_DATA_ALT +from .const import ( + CONFIG_V1, + ENERGY_HISTORY, + LIVE_STATUS, + PRODUCTS_MODERN, + UNIQUE_ID, + VEHICLE_DATA_ALT, +) -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, async_fire_time_changed ERRORS = [ (InvalidToken, ConfigEntryState.SETUP_ERROR), @@ -319,9 +334,7 @@ async def test_migrate_from_version_1_success(hass: HomeAssistant) -> None: await hass.config_entries.async_setup(mock_entry.entry_id) await hass.async_block_till_done() - mock_migrate.assert_called_once_with( - CLIENT_ID, CONFIG_V1[CONF_ACCESS_TOKEN], hass.config.location_name - ) + mock_migrate.assert_called_once_with(CLIENT_ID, hass.config.location_name) assert mock_entry is not None assert mock_entry.version == 2 @@ -356,9 +369,7 @@ async def test_migrate_from_version_1_token_endpoint_error(hass: HomeAssistant) await hass.config_entries.async_setup(mock_entry.entry_id) await hass.async_block_till_done() - mock_migrate.assert_called_once_with( - CLIENT_ID, CONFIG_V1[CONF_ACCESS_TOKEN], hass.config.location_name - ) + mock_migrate.assert_called_once_with(CLIENT_ID, hass.config.location_name) entry = hass.config_entries.async_get_entry(mock_entry.entry_id) assert entry is not None @@ -430,3 +441,206 @@ async def test_migrate_from_future_version_fails(hass: HomeAssistant) -> None: assert entry is not None assert entry.state is ConfigEntryState.MIGRATION_ERROR assert entry.version == 3 # Version should remain unchanged + + +async def test_oauth_implementation_not_available(hass: HomeAssistant) -> None: + """Test that missing OAuth implementation triggers reauth.""" + mock_entry = MockConfigEntry( + domain=DOMAIN, + version=2, + unique_id=UNIQUE_ID, + data={ + "auth_implementation": DOMAIN, + "token": { + "access_token": "test_access_token", + "refresh_token": "test_refresh_token", + "expires_at": int(time.time()) + 3600, + }, + }, + ) + mock_entry.add_to_hass(hass) + + # Mock the implementation lookup to raise ValueError + with patch( + "homeassistant.components.teslemetry.async_get_config_entry_implementation", + side_effect=ValueError("Implementation not available"), + ): + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() + + entry = hass.config_entries.async_get_entry(mock_entry.entry_id) + assert entry is not None + # Should trigger reauth, not just fail silently + assert entry.state is ConfigEntryState.SETUP_ERROR + + +RETRY_EXCEPTIONS = [ + (RateLimited(data={"after": 5}), 5.0), + (InvalidResponse(), 10.0), +] + + +@pytest.mark.parametrize(("exception", "expected_retry_after"), RETRY_EXCEPTIONS) +async def test_site_info_retry_exceptions( + hass: HomeAssistant, + mock_site_info: AsyncMock, + exception: TeslaFleetError, + expected_retry_after: float, +) -> None: + """Test UpdateFailed with retry_after for site info coordinator.""" + mock_site_info.side_effect = exception + entry = await setup_platform(hass) + # Retry exceptions during first refresh cause setup retry + assert entry.state is ConfigEntryState.SETUP_RETRY + # API should only be called once (no manual retries) + assert mock_site_info.call_count == 1 + + +@pytest.mark.parametrize(("exception", "expected_retry_after"), RETRY_EXCEPTIONS) +async def test_vehicle_data_retry_exceptions( + hass: HomeAssistant, + mock_vehicle_data: AsyncMock, + mock_legacy: AsyncMock, + exception: TeslaFleetError, + expected_retry_after: float, +) -> None: + """Test UpdateFailed with retry_after for vehicle data coordinator.""" + mock_vehicle_data.side_effect = exception + entry = await setup_platform(hass) + # Retry exceptions during first refresh cause setup retry + assert entry.state is ConfigEntryState.SETUP_RETRY + # API should only be called once (no manual retries) + assert mock_vehicle_data.call_count == 1 + + +@pytest.mark.parametrize(("exception", "expected_retry_after"), RETRY_EXCEPTIONS) +async def test_live_status_coordinator_retry_exceptions( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + mock_live_status: AsyncMock, + exception: TeslaFleetError, + expected_retry_after: float, +) -> None: + """Test live status coordinator raises UpdateFailed with retry_after.""" + call_count = 0 + + def live_status_side_effect(): + nonlocal call_count + call_count += 1 + if call_count == 1: + return deepcopy(LIVE_STATUS) # Initial call succeeds + if call_count == 2: + raise exception # Second call raises exception + return deepcopy(LIVE_STATUS) # Subsequent calls succeed + + mock_live_status.side_effect = live_status_side_effect + + entry = await setup_platform(hass) + assert entry.state is ConfigEntryState.LOADED + assert call_count == 1 + + # Trigger coordinator refresh - this will raise the exception + freezer.tick(ENERGY_LIVE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # API was called exactly once for this refresh (no manual retry loop) + assert call_count == 2 + # Entry stays loaded - UpdateFailed with retry_after doesn't break the entry + assert entry.state is ConfigEntryState.LOADED + + +@pytest.mark.parametrize(("exception", "expected_retry_after"), RETRY_EXCEPTIONS) +async def test_energy_history_coordinator_retry_exceptions( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + mock_energy_history: AsyncMock, + exception: TeslaFleetError, + expected_retry_after: float, +) -> None: + """Test energy history coordinator raises UpdateFailed with retry_after.""" + call_count = 0 + + def energy_history_side_effect(*args, **kwargs): + nonlocal call_count + call_count += 1 + if call_count == 1: + raise exception # First call raises exception + return ENERGY_HISTORY # Subsequent calls succeed + + mock_energy_history.side_effect = energy_history_side_effect + + entry = await setup_platform(hass) + assert entry.state is ConfigEntryState.LOADED + # Energy history doesn't have first_refresh during setup + assert call_count == 0 + + # Trigger first coordinator refresh - this will raise the exception + freezer.tick(ENERGY_HISTORY_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # API was called exactly once (no manual retry loop) + assert call_count == 1 + # Entry stays loaded - UpdateFailed with retry_after doesn't break the entry + assert entry.state is ConfigEntryState.LOADED + + +async def test_live_status_auth_error( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, +) -> None: + """Test live status coordinator handles auth errors.""" + call_count = 0 + + def live_status_side_effect(): + nonlocal call_count + call_count += 1 + if call_count == 1: + return deepcopy(LIVE_STATUS) + raise InvalidToken + + with patch( + "tesla_fleet_api.tesla.energysite.EnergySite.live_status", + side_effect=live_status_side_effect, + ): + entry = await setup_platform(hass) + assert entry.state is ConfigEntryState.LOADED + + # Trigger a coordinator refresh by advancing time + freezer.tick(ENERGY_LIVE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # Auth error triggers reauth flow + assert entry.state is ConfigEntryState.LOADED + + +async def test_live_status_generic_error( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, +) -> None: + """Test live status coordinator handles generic TeslaFleetError.""" + call_count = 0 + + def live_status_side_effect(): + nonlocal call_count + call_count += 1 + if call_count == 1: + return deepcopy(LIVE_STATUS) + raise TeslaFleetError + + with patch( + "tesla_fleet_api.tesla.energysite.EnergySite.live_status", + side_effect=live_status_side_effect, + ): + entry = await setup_platform(hass) + assert entry.state is ConfigEntryState.LOADED + + # Trigger a coordinator refresh by advancing time + freezer.tick(ENERGY_LIVE_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + # Entry stays loaded but coordinator will have failed + assert entry.state is ConfigEntryState.LOADED diff --git a/tests/components/teslemetry/test_services.py b/tests/components/teslemetry/test_services.py index fecb8db0092..8137946aa3a 100644 --- a/tests/components/teslemetry/test_services.py +++ b/tests/components/teslemetry/test_services.py @@ -63,6 +63,40 @@ async def test_services( "sensor.energy_site_battery_power" ).device_id + # Test set_scheduled_charging with enable=False (time should default to 0) + with patch( + "tesla_fleet_api.teslemetry.Vehicle.set_scheduled_charging", + return_value=COMMAND_OK, + ) as set_scheduled_charging_off: + await hass.services.async_call( + DOMAIN, + SERVICE_SET_SCHEDULED_CHARGING, + { + CONF_DEVICE_ID: vehicle_device, + ATTR_ENABLE: False, + }, + blocking=True, + ) + set_scheduled_charging_off.assert_called_once_with(enable=False, time=0) + + # Test set_scheduled_departure with enable=False (times should default to 0) + with patch( + "tesla_fleet_api.teslemetry.Vehicle.set_scheduled_departure", + return_value=COMMAND_OK, + ) as set_scheduled_departure_off: + await hass.services.async_call( + DOMAIN, + SERVICE_SET_SCHEDULED_DEPARTURE, + { + CONF_DEVICE_ID: vehicle_device, + ATTR_ENABLE: False, + }, + blocking=True, + ) + set_scheduled_departure_off.assert_called_once_with( + False, False, False, 0, False, False, 0 + ) + with patch( "tesla_fleet_api.teslemetry.Vehicle.navigation_gps_request", return_value=COMMAND_OK, @@ -308,6 +342,8 @@ async def test_service_validation_errors( """Tests that the custom services handle bad data.""" await setup_platform(hass) + entity_registry = er.async_get(hass) + vehicle_device = entity_registry.async_get("sensor.test_charging").device_id # Bad device ID with pytest.raises(ServiceValidationError): @@ -320,3 +356,39 @@ async def test_service_validation_errors( }, blocking=True, ) + + # Test set_scheduled_charging validation error (enable=True but no time) + with pytest.raises(ServiceValidationError): + await hass.services.async_call( + DOMAIN, + SERVICE_SET_SCHEDULED_CHARGING, + { + CONF_DEVICE_ID: vehicle_device, + ATTR_ENABLE: True, + }, + blocking=True, + ) + + # Test set_scheduled_departure validation error (preconditioning_enabled=True but no departure_time) + with pytest.raises(ServiceValidationError): + await hass.services.async_call( + DOMAIN, + SERVICE_SET_SCHEDULED_DEPARTURE, + { + CONF_DEVICE_ID: vehicle_device, + ATTR_PRECONDITIONING_ENABLED: True, + }, + blocking=True, + ) + + # Test set_scheduled_departure validation error (off_peak_charging_enabled=True but no end_off_peak_time) + with pytest.raises(ServiceValidationError): + await hass.services.async_call( + DOMAIN, + SERVICE_SET_SCHEDULED_DEPARTURE, + { + CONF_DEVICE_ID: vehicle_device, + ATTR_OFF_PEAK_CHARGING_ENABLED: True, + }, + blocking=True, + ) diff --git a/tests/components/tessie/snapshots/test_binary_sensor.ambr b/tests/components/tessie/snapshots/test_binary_sensor.ambr index e1875626f76..4374cb65c14 100644 --- a/tests/components/tessie/snapshots/test_binary_sensor.ambr +++ b/tests/components/tessie/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup capable', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services active', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services enabled', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storm watch active', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto seat climate left', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto seat climate right', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto steering wheel heater', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery heater', 'options': dict({ }), 'original_device_class': , @@ -405,6 +413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection', 'options': dict({ }), 'original_device_class': , @@ -454,6 +463,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cabin overheat protection actively cooling', 'options': dict({ }), 'original_device_class': , @@ -503,6 +513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable', 'options': dict({ }), 'original_device_class': , @@ -552,6 +563,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -601,6 +613,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dashcam', 'options': dict({ }), 'original_device_class': , @@ -650,6 +663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front driver door', 'options': dict({ }), 'original_device_class': , @@ -699,6 +713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front driver window', 'options': dict({ }), 'original_device_class': , @@ -748,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front passenger door', 'options': dict({ }), 'original_device_class': , @@ -797,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Front passenger window', 'options': dict({ }), 'original_device_class': , @@ -846,6 +863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preconditioning enabled', 'options': dict({ }), 'original_device_class': None, @@ -894,6 +912,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear driver door', 'options': dict({ }), 'original_device_class': , @@ -943,6 +962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear driver window', 'options': dict({ }), 'original_device_class': , @@ -992,6 +1012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear passenger door', 'options': dict({ }), 'original_device_class': , @@ -1041,6 +1062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rear passenger window', 'options': dict({ }), 'original_device_class': , @@ -1090,6 +1112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Scheduled charging pending', 'options': dict({ }), 'original_device_class': None, @@ -1138,6 +1161,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -1187,6 +1211,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning front left', 'options': dict({ }), 'original_device_class': , @@ -1236,6 +1261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning front right', 'options': dict({ }), 'original_device_class': , @@ -1285,6 +1311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning rear left', 'options': dict({ }), 'original_device_class': , @@ -1334,6 +1361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure warning rear right', 'options': dict({ }), 'original_device_class': , @@ -1383,6 +1411,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip charging', 'options': dict({ }), 'original_device_class': None, @@ -1431,6 +1460,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'User present', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tessie/snapshots/test_button.ambr b/tests/components/tessie/snapshots/test_button.ambr index fda5fe9a59f..e0fcd9e4c5a 100644 --- a/tests/components/tessie/snapshots/test_button.ambr +++ b/tests/components/tessie/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash lights', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Homelink', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk horn', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Keyless driving', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Play fart', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wake', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tessie/snapshots/test_climate.ambr b/tests/components/tessie/snapshots/test_climate.ambr index 50756cef338..30d49bb1cdb 100644 --- a/tests/components/tessie/snapshots/test_climate.ambr +++ b/tests/components/tessie/snapshots/test_climate.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Climate', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tessie/snapshots/test_cover.ambr b/tests/components/tessie/snapshots/test_cover.ambr index bcb2a13dbef..808291ac42b 100644 --- a/tests/components/tessie/snapshots/test_cover.ambr +++ b/tests/components/tessie/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge port door', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frunk', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trunk', 'options': dict({ }), 'original_device_class': , @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vent windows', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tessie/snapshots/test_device_tracker.ambr b/tests/components/tessie/snapshots/test_device_tracker.ambr index 5887d1abd2b..a0499dfe085 100644 --- a/tests/components/tessie/snapshots/test_device_tracker.ambr +++ b/tests/components/tessie/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Route', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tessie/snapshots/test_lock.ambr b/tests/components/tessie/snapshots/test_lock.ambr index 57cbcd4434f..3c8e37d1f27 100644 --- a/tests/components/tessie/snapshots/test_lock.ambr +++ b/tests/components/tessie/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge cable lock', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tessie/snapshots/test_media_player.ambr b/tests/components/tessie/snapshots/test_media_player.ambr index 69a5ca4b86b..43edb9a6643 100644 --- a/tests/components/tessie/snapshots/test_media_player.ambr +++ b/tests/components/tessie/snapshots/test_media_player.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Media player', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tessie/snapshots/test_number.ambr b/tests/components/tessie/snapshots/test_number.ambr index dd81c439e0c..cfe207dfaa2 100644 --- a/tests/components/tessie/snapshots/test_number.ambr +++ b/tests/components/tessie/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backup reserve', 'options': dict({ }), 'original_device_class': , @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Off-grid reserve', 'options': dict({ }), 'original_device_class': , @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge current', 'options': dict({ }), 'original_device_class': , @@ -204,6 +207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge limit', 'options': dict({ }), 'original_device_class': , @@ -263,6 +267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed limit', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tessie/snapshots/test_select.ambr b/tests/components/tessie/snapshots/test_select.ambr index 6a08b7b2b91..608896ceea0 100644 --- a/tests/components/tessie/snapshots/test_select.ambr +++ b/tests/components/tessie/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow export', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Operation mode', 'options': dict({ }), 'original_device_class': None, @@ -145,6 +147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat cooler left', 'options': dict({ }), 'original_device_class': None, @@ -206,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat cooler right', 'options': dict({ }), 'original_device_class': None, @@ -267,6 +271,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater left', 'options': dict({ }), 'original_device_class': None, @@ -328,6 +333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear center', 'options': dict({ }), 'original_device_class': None, @@ -389,6 +395,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear left', 'options': dict({ }), 'original_device_class': None, @@ -450,6 +457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater rear right', 'options': dict({ }), 'original_device_class': None, @@ -511,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seat heater right', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tessie/snapshots/test_sensor.ambr b/tests/components/tessie/snapshots/test_sensor.ambr index ca2a379c5f2..932189e9583 100644 --- a/tests/components/tessie/snapshots/test_sensor.ambr +++ b/tests/components/tessie/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Generator power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grid services power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -317,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -376,6 +382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Percentage charged', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -432,6 +439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -491,6 +499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total pack energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -548,6 +557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VPP backup reserve', 'options': dict({ }), 'original_device_class': , @@ -600,6 +610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery level', 'options': dict({ }), 'original_device_class': , @@ -653,6 +664,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery range', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -712,6 +724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery range estimate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -771,6 +784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery range ideal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -830,6 +844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge energy added', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -886,6 +901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -945,6 +961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1001,6 +1018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1057,6 +1075,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charger voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1120,6 +1139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -1177,6 +1197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Destination', 'options': dict({ }), 'original_device_class': None, @@ -1227,6 +1248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to arrival', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1286,6 +1308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Driver temperature setting', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1342,6 +1365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1398,6 +1422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1457,6 +1482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1513,6 +1539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Passenger temperature setting', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1569,6 +1596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1630,6 +1658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Shift state', 'options': dict({ }), 'original_device_class': , @@ -1687,6 +1716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1746,6 +1776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State of charge at arrival', 'options': dict({ }), 'original_device_class': , @@ -1797,6 +1828,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to arrival', 'options': dict({ }), 'original_device_class': , @@ -1846,6 +1878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to full charge', 'options': dict({ }), 'original_device_class': , @@ -1897,6 +1930,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure front left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1956,6 +1990,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure front right', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2015,6 +2050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure rear left', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2074,6 +2110,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire pressure rear right', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2133,6 +2170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Traffic delay', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2189,6 +2227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2248,6 +2287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2318,6 +2358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -2392,6 +2433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -2453,6 +2495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, @@ -2501,6 +2544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vehicle', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tessie/snapshots/test_switch.ambr b/tests/components/tessie/snapshots/test_switch.ambr index e0a59cd967b..d9607967ffa 100644 --- a/tests/components/tessie/snapshots/test_switch.ambr +++ b/tests/components/tessie/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Allow charging from grid', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Storm watch', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge', 'options': dict({ }), 'original_device_class': , @@ -165,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrost mode', 'options': dict({ }), 'original_device_class': , @@ -214,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sentry mode', 'options': dict({ }), 'original_device_class': , @@ -263,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steering wheel heater', 'options': dict({ }), 'original_device_class': , @@ -312,6 +318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valet mode', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tessie/snapshots/test_update.ambr b/tests/components/tessie/snapshots/test_update.ambr index ff298f97ecd..53c6574588e 100644 --- a/tests/components/tessie/snapshots/test_update.ambr +++ b/tests/components/tessie/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Update', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/text/test_device_action.py b/tests/components/text/test_device_action.py index 5766e5dce2a..4cd368e737c 100644 --- a/tests/components/text/test_device_action.py +++ b/tests/components/text/test_device_action.py @@ -24,11 +24,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/text/test_trigger.py b/tests/components/text/test_trigger.py index 89e4a1cdc37..547544d9449 100644 --- a/tests/components/text/test_trigger.py +++ b/tests/components/text/test_trigger.py @@ -1,8 +1,5 @@ """Test text trigger.""" -from collections.abc import Generator -from unittest.mock import patch - import pytest from homeassistant.const import ( @@ -14,7 +11,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, set_or_remove_state, @@ -22,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_texts(hass: HomeAssistant) -> list[str]: """Create multiple text entities associated with different targets.""" @@ -57,7 +39,7 @@ async def test_text_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("text"), @@ -124,7 +106,7 @@ async def test_text_state_trigger_behavior_any( entity_id: str, entities_in_target: int, trigger: str, - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the text state trigger fires when any text state changes to a specific state.""" other_entity_ids = set(target_texts) - {entity_id} diff --git a/tests/components/tibber/conftest.py b/tests/components/tibber/conftest.py index 2f514cdeb13..bc6ecd7d8a9 100644 --- a/tests/components/tibber/conftest.py +++ b/tests/components/tibber/conftest.py @@ -2,6 +2,7 @@ from collections.abc import AsyncGenerator import time +from typing import Any from unittest.mock import AsyncMock, MagicMock, patch import pytest @@ -13,7 +14,7 @@ from homeassistant.components.application_credentials import ( ) from homeassistant.components.recorder import Recorder from homeassistant.components.tibber.const import AUTH_IMPLEMENTATION, DOMAIN -from homeassistant.const import CONF_ACCESS_TOKEN +from homeassistant.const import CONF_ACCESS_TOKEN, Platform from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component @@ -26,10 +27,102 @@ def create_tibber_device( name: str = "Test Device", brand: str = "Tibber", model: str = "Gen1", - value: float | None = 72.0, home_id: str = "home-id", + state_of_charge: float | None = None, + connector_status: str | None = None, + charging_status: str | None = None, + device_status: str | None = None, + is_online: str | None = None, + sensor_values: dict[str, Any] | None = None, ) -> tibber.data_api.TibberDevice: - """Create a fake Tibber Data API device.""" + """Create a fake Tibber Data API device. + + Args: + device_id: Device ID. + external_id: External device ID. + name: Device name. + brand: Device brand. + model: Device model. + home_id: Home ID. + state_of_charge: Battery state of charge (for regular sensors). + connector_status: Connector status (for binary sensors). + charging_status: Charging status (for binary sensors). + device_status: Device on/off status (for binary sensors). + is_online: Device online status (for binary sensors). + sensor_values: Dictionary mapping sensor IDs to their values for additional sensors. + """ + capabilities = [] + + # Add regular sensor capabilities + if state_of_charge is not None: + capabilities.append( + { + "id": "storage.stateOfCharge", + "value": state_of_charge, + "description": "State of charge", + "unit": "%", + } + ) + capabilities.append( + { + "id": "unknown.sensor.id", + "value": None, + "description": "Unknown", + "unit": "", + } + ) + + if connector_status is not None: + capabilities.append( + { + "id": "connector.status", + "value": connector_status, + "description": "Connector status", + "unit": "", + } + ) + + if charging_status is not None: + capabilities.append( + { + "id": "charging.status", + "value": charging_status, + "description": "Charging status", + "unit": "", + } + ) + + if device_status is not None: + capabilities.append( + { + "id": "onOff", + "value": device_status, + "description": "Device status", + "unit": "", + } + ) + + if is_online is not None: + capabilities.append( + { + "id": "isOnline", + "value": is_online, + "description": "Device online status", + "unit": "", + } + ) + + if sensor_values: + for sensor_id, value in sensor_values.items(): + capabilities.append( + { + "id": sensor_id, + "value": value, + "description": sensor_id.replace(".", " ").title(), + "unit": "", + } + ) + device_data = { "id": device_id, "externalId": external_id, @@ -38,20 +131,7 @@ def create_tibber_device( "brand": brand, "model": model, }, - "capabilities": [ - { - "id": "storage.stateOfCharge", - "value": value, - "description": "State of charge", - "unit": "%", - }, - { - "id": "unknown.sensor.id", - "value": None, - "description": "Unknown", - "unit": "", - }, - ], + "capabilities": capabilities, } return tibber.data_api.TibberDevice(device_data, home_id=home_id) @@ -144,3 +224,16 @@ async def setup_credentials(hass: HomeAssistant) -> None: ClientCredential("test-client-id", "test-client-secret"), DOMAIN, ) + + +@pytest.fixture +def platforms() -> list[Platform]: + """Fixture to specify platforms to test.""" + return [Platform.BINARY_SENSOR, Platform.NOTIFY, Platform.SENSOR] + + +@pytest.fixture(autouse=True) +async def mock_patch_platforms(platforms: list[Platform]) -> AsyncGenerator[None]: + """Fixture to set up platforms for tests.""" + with patch(f"homeassistant.components.{DOMAIN}.PLATFORMS", platforms): + yield diff --git a/tests/components/tibber/snapshots/test_binary_sensor.ambr b/tests/components/tibber/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..df30ebb050d --- /dev/null +++ b/tests/components/tibber/snapshots/test_binary_sensor.ambr @@ -0,0 +1,201 @@ +# serializer version: 1 +# name: test_binary_sensor_snapshot[binary_sensor.test_device_charging-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.test_device_charging', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Charging', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging', + 'platform': 'tibber', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'device-id_charging.status', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_charging-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery_charging', + 'friendly_name': 'Test Device Charging', + }), + 'context': , + 'entity_id': 'binary_sensor.test_device_charging', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_connectivity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.test_device_connectivity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Connectivity', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Connectivity', + 'platform': 'tibber', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'device-id_isOnline', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_connectivity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'connectivity', + 'friendly_name': 'Test Device Connectivity', + }), + 'context': , + 'entity_id': 'binary_sensor.test_device_connectivity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_plug-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.test_device_plug', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Plug', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Plug', + 'platform': 'tibber', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'device-id_connector.status', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_plug-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'plug', + 'friendly_name': 'Test Device Plug', + }), + 'context': , + 'entity_id': 'binary_sensor.test_device_plug', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.test_device_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power', + 'platform': 'tibber', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'device-id_onOff', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensor_snapshot[binary_sensor.test_device_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Test Device Power', + }), + 'context': , + 'entity_id': 'binary_sensor.test_device_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- diff --git a/tests/components/tibber/test_binary_sensor.py b/tests/components/tibber/test_binary_sensor.py new file mode 100644 index 00000000000..3aef9cbcffd --- /dev/null +++ b/tests/components/tibber/test_binary_sensor.py @@ -0,0 +1,102 @@ +"""Tests for the Tibber binary sensors.""" + +from __future__ import annotations + +from unittest.mock import AsyncMock + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.recorder import Recorder +from homeassistant.const import STATE_OFF, STATE_ON, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from .conftest import create_tibber_device + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.fixture +def platforms() -> list[Platform]: + """Fixture to specify platforms to test.""" + return [Platform.BINARY_SENSOR] + + +async def test_binary_sensor_snapshot( + recorder_mock: Recorder, + hass: HomeAssistant, + config_entry: MockConfigEntry, + data_api_client_mock: AsyncMock, + setup_credentials: None, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """Test binary sensor entities against snapshot.""" + device = create_tibber_device( + connector_status="connected", + charging_status="charging", + device_status="on", + is_online="true", + ) + data_api_client_mock.get_all_devices = AsyncMock(return_value={"device-id": device}) + data_api_client_mock.update_devices = AsyncMock(return_value={"device-id": device}) + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) + + +@pytest.mark.parametrize( + ( + "entity_suffix", + "connector_status", + "charging_status", + "device_status", + "is_online", + "expected_state", + ), + [ + ("plug", "connected", None, None, None, STATE_ON), + ("plug", "disconnected", None, None, None, STATE_OFF), + ("charging", None, "charging", None, None, STATE_ON), + ("charging", None, "idle", None, None, STATE_OFF), + ("power", None, None, "on", None, STATE_ON), + ("power", None, None, "off", None, STATE_OFF), + ("connectivity", None, None, None, "true", STATE_ON), + ("connectivity", None, None, None, "True", STATE_ON), + ("connectivity", None, None, None, "false", STATE_OFF), + ("connectivity", None, None, None, "False", STATE_OFF), + ], +) +async def test_binary_sensor_states( + recorder_mock: Recorder, + hass: HomeAssistant, + config_entry: MockConfigEntry, + data_api_client_mock: AsyncMock, + setup_credentials: None, + entity_suffix: str, + connector_status: str | None, + charging_status: str | None, + device_status: str | None, + is_online: str | None, + expected_state: str, +) -> None: + """Test binary sensor state values.""" + device = create_tibber_device( + connector_status=connector_status, + charging_status=charging_status, + device_status=device_status, + is_online=is_online, + ) + data_api_client_mock.get_all_devices = AsyncMock(return_value={"device-id": device}) + data_api_client_mock.update_devices = AsyncMock(return_value={"device-id": device}) + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + entity_id = f"binary_sensor.test_device_{entity_suffix}" + state = hass.states.get(entity_id) + assert state is not None + assert state.state == expected_state diff --git a/tests/components/tibber/test_sensor.py b/tests/components/tibber/test_sensor.py index 83b55931363..21b0f55cf65 100644 --- a/tests/components/tibber/test_sensor.py +++ b/tests/components/tibber/test_sensor.py @@ -4,6 +4,8 @@ from __future__ import annotations from unittest.mock import AsyncMock +import pytest + from homeassistant.components.recorder import Recorder from homeassistant.components.tibber.const import DOMAIN from homeassistant.core import HomeAssistant @@ -24,10 +26,10 @@ async def test_data_api_sensors_are_created( ) -> None: """Ensure Data API sensors are created and expose values from the coordinator.""" data_api_client_mock.get_all_devices = AsyncMock( - return_value={"device-id": create_tibber_device(value=72.0)} + return_value={"device-id": create_tibber_device(state_of_charge=72.0)} ) data_api_client_mock.update_devices = AsyncMock( - return_value={"device-id": create_tibber_device(value=83.0)} + return_value={"device-id": create_tibber_device(state_of_charge=83.0)} ) await hass.config_entries.async_setup(config_entry.entry_id) @@ -43,3 +45,127 @@ async def test_data_api_sensors_are_created( state = hass.states.get(entity_id) assert state is not None assert float(state.state) == 83.0 + + +@pytest.mark.parametrize( + ("sensor_id", "expected_value", "description"), + [ + ("storage.ratedCapacity", 10000.0, "Storage rated capacity"), + ("storage.ratedPower", 5000.0, "Storage rated power"), + ("storage.availableEnergy", 7500.0, "Storage available energy"), + ("powerFlow.battery.power", 2500.0, "Battery power flow"), + ("powerFlow.grid.power", 1500.0, "Grid power flow"), + ("powerFlow.load.power", 4000.0, "Load power flow"), + ("powerFlow.toGrid", 25.5, "Power flow to grid percentage"), + ("powerFlow.toLoad", 60.0, "Power flow to load percentage"), + ("powerFlow.fromGrid", 15.0, "Power flow from grid percentage"), + ("powerFlow.fromLoad", 10.0, "Power flow from load percentage"), + ("energyFlow.hour.battery.charged", 2000.0, "Hourly battery charged"), + ("energyFlow.hour.battery.discharged", 1500.0, "Hourly battery discharged"), + ("energyFlow.hour.grid.imported", 1000.0, "Hourly grid imported"), + ("energyFlow.hour.grid.exported", 800.0, "Hourly grid exported"), + ("energyFlow.hour.load.consumed", 3000.0, "Hourly load consumed"), + ("energyFlow.hour.load.generated", 200.0, "Hourly load generated"), + ("energyFlow.month.battery.charged", 50000.0, "Monthly battery charged"), + ("energyFlow.month.battery.discharged", 40000.0, "Monthly battery discharged"), + ("energyFlow.month.grid.imported", 25000.0, "Monthly grid imported"), + ("energyFlow.month.grid.exported", 20000.0, "Monthly grid exported"), + ("energyFlow.month.load.consumed", 60000.0, "Monthly load consumed"), + ("energyFlow.month.load.generated", 5000.0, "Monthly load generated"), + ("range.remaining", 250.5, "Remaining range"), + ("charging.current.max", 32.0, "Max charging current"), + ("charging.current.offlineFallback", 16.0, "Offline fallback charging current"), + ("temp.setpoint", 22.5, "Temperature setpoint"), + ("temp.current", 21.0, "Current temperature"), + ("temp.comfort", 20.5, "Comfort temperature"), + ("grid.phaseCount", 3.0, "Grid phase count"), + ], +) +async def test_new_data_api_sensor_values( + recorder_mock: Recorder, + hass: HomeAssistant, + config_entry: MockConfigEntry, + data_api_client_mock: AsyncMock, + setup_credentials: None, + entity_registry: er.EntityRegistry, + sensor_id: str, + expected_value: float, + description: str, +) -> None: + """Test individual new Data API sensor values.""" + device = create_tibber_device(sensor_values={sensor_id: expected_value}) + data_api_client_mock.get_all_devices = AsyncMock(return_value={"device-id": device}) + data_api_client_mock.update_devices = AsyncMock(return_value={"device-id": device}) + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + unique_id = f"external-id_{sensor_id}" + entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, unique_id) + assert entity_id is not None, f"Entity not found for {description}" + + state = hass.states.get(entity_id) + assert state is not None, f"State not found for {description}" + assert float(state.state) == expected_value, ( + f"Expected {expected_value} for {description}, got {state.state}" + ) + + +async def test_new_data_api_sensors_with_disabled_by_default( + recorder_mock: Recorder, + hass: HomeAssistant, + config_entry: MockConfigEntry, + data_api_client_mock: AsyncMock, + setup_credentials: None, + entity_registry: er.EntityRegistry, +) -> None: + """Test that sensors with entity_registry_enabled_default=False are disabled by default.""" + sensor_values = { + "cellular.rssi": -75.0, + "energyFlow.hour.battery.source.grid": 500.0, + "energyFlow.hour.battery.source.load": 300.0, + "energyFlow.hour.load.source.battery": 700.0, + "energyFlow.hour.load.source.grid": 500.0, + "energyFlow.month.battery.source.grid": 10000.0, + "energyFlow.month.battery.source.battery": 5000.0, + "energyFlow.month.battery.source.load": 8000.0, + "energyFlow.month.grid.source.battery": 3000.0, + "energyFlow.month.grid.source.grid": 1000.0, + "energyFlow.month.grid.source.load": 2000.0, + "energyFlow.month.load.source.battery": 15000.0, + "energyFlow.month.load.source.grid": 10000.0, + } + + device = create_tibber_device(sensor_values=sensor_values) + data_api_client_mock.get_all_devices = AsyncMock(return_value={"device-id": device}) + data_api_client_mock.update_devices = AsyncMock(return_value={"device-id": device}) + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + disabled_sensors = [ + "cellular.rssi", + "energyFlow.hour.battery.source.grid", + "energyFlow.hour.battery.source.load", + "energyFlow.hour.load.source.battery", + "energyFlow.hour.load.source.grid", + "energyFlow.month.battery.source.grid", + "energyFlow.month.battery.source.battery", + "energyFlow.month.battery.source.load", + "energyFlow.month.grid.source.battery", + "energyFlow.month.grid.source.grid", + "energyFlow.month.grid.source.load", + "energyFlow.month.load.source.battery", + "energyFlow.month.load.source.grid", + ] + + for sensor_id in disabled_sensors: + unique_id = f"external-id_{sensor_id}" + entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, unique_id) + assert entity_id is not None, f"Entity not found for sensor {sensor_id}" + + entity_entry = entity_registry.async_get(entity_id) + assert entity_entry is not None + assert entity_entry.disabled, ( + f"Sensor {sensor_id} should be disabled by default" + ) diff --git a/tests/components/tile/snapshots/test_binary_sensor.ambr b/tests/components/tile/snapshots/test_binary_sensor.ambr index 1a8cbdbff36..f45151a120c 100644 --- a/tests/components/tile/snapshots/test_binary_sensor.ambr +++ b/tests/components/tile/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lost', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tile/snapshots/test_device_tracker.ambr b/tests/components/tile/snapshots/test_device_tracker.ambr index 069d66a42e6..8c598c35f84 100644 --- a/tests/components/tile/snapshots/test_device_tracker.ambr +++ b/tests/components/tile/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tilt_pi/snapshots/test_sensor.ambr b/tests/components/tilt_pi/snapshots/test_sensor.ambr index bcee6881d75..ce288d7b8c0 100644 --- a/tests/components/tilt_pi/snapshots/test_sensor.ambr +++ b/tests/components/tilt_pi/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gravity', 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gravity', 'options': dict({ }), 'original_device_class': None, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/togrill/snapshots/test_event.ambr b/tests/components/togrill/snapshots/test_event.ambr index e579c0745bc..3d828e0eb48 100644 --- a/tests/components/togrill/snapshots/test_event.ambr +++ b/tests/components/togrill/snapshots/test_event.ambr @@ -35,6 +35,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Event', 'options': dict({ }), 'original_device_class': None, @@ -113,6 +114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Event', 'options': dict({ }), 'original_device_class': None, @@ -191,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Event', 'options': dict({ }), 'original_device_class': None, @@ -269,6 +272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Event', 'options': dict({ }), 'original_device_class': None, @@ -347,6 +351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Event', 'options': dict({ }), 'original_device_class': None, @@ -425,6 +430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Event', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/togrill/snapshots/test_number.ambr b/tests/components/togrill/snapshots/test_number.ambr index 8525cd783df..972158ef629 100644 --- a/tests/components/togrill/snapshots/test_number.ambr +++ b/tests/components/togrill/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm interval', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum temperature', 'options': dict({ }), 'original_device_class': , @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum temperature', 'options': dict({ }), 'original_device_class': , @@ -204,6 +207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ }), 'original_device_class': , @@ -264,6 +268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum temperature', 'options': dict({ }), 'original_device_class': , @@ -324,6 +329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum temperature', 'options': dict({ }), 'original_device_class': , @@ -384,6 +390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ }), 'original_device_class': , @@ -444,6 +451,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm interval', 'options': dict({ }), 'original_device_class': , @@ -503,6 +511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum temperature', 'options': dict({ }), 'original_device_class': , @@ -563,6 +572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum temperature', 'options': dict({ }), 'original_device_class': , @@ -623,6 +633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ }), 'original_device_class': , @@ -683,6 +694,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum temperature', 'options': dict({ }), 'original_device_class': , @@ -743,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum temperature', 'options': dict({ }), 'original_device_class': , @@ -803,6 +816,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/togrill/snapshots/test_select.ambr b/tests/components/togrill/snapshots/test_select.ambr index 7755b51d2f6..7cb5aca46d6 100644 --- a/tests/components/togrill/snapshots/test_select.ambr +++ b/tests/components/togrill/snapshots/test_select.ambr @@ -39,6 +39,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grill type', 'options': dict({ }), 'original_device_class': None, @@ -114,6 +115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Taste', 'options': dict({ }), 'original_device_class': None, @@ -189,6 +191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grill type', 'options': dict({ }), 'original_device_class': None, @@ -264,6 +267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Taste', 'options': dict({ }), 'original_device_class': None, @@ -339,6 +343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grill type', 'options': dict({ }), 'original_device_class': None, @@ -414,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Taste', 'options': dict({ }), 'original_device_class': None, @@ -489,6 +495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grill type', 'options': dict({ }), 'original_device_class': None, @@ -564,6 +571,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Taste', 'options': dict({ }), 'original_device_class': None, @@ -639,6 +647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grill type', 'options': dict({ }), 'original_device_class': None, @@ -714,6 +723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Taste', 'options': dict({ }), 'original_device_class': None, @@ -789,6 +799,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Grill type', 'options': dict({ }), 'original_device_class': None, @@ -864,6 +875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Taste', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/togrill/snapshots/test_sensor.ambr b/tests/components/togrill/snapshots/test_sensor.ambr index 3f1d1fd196d..cb61b9d4578 100644 --- a/tests/components/togrill/snapshots/test_sensor.ambr +++ b/tests/components/togrill/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -638,6 +649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -694,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -750,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -806,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -862,6 +877,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -918,6 +934,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -974,6 +991,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1030,6 +1048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1086,6 +1105,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1142,6 +1162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1198,6 +1219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1254,6 +1276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1310,6 +1333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1366,6 +1390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1422,6 +1447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1478,6 +1504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1534,6 +1561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1590,6 +1618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ambient temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1646,6 +1675,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1702,6 +1732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1758,6 +1789,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/totalconnect/snapshots/test_alarm_control_panel.ambr b/tests/components/totalconnect/snapshots/test_alarm_control_panel.ambr index a79fe3832cd..a917b5df7b5 100644 --- a/tests/components/totalconnect/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/totalconnect/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Partition 2', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/totalconnect/snapshots/test_binary_sensor.ambr b/tests/components/totalconnect/snapshots/test_binary_sensor.ambr index 55702b06acc..7492aeae63b 100644 --- a/tests/components/totalconnect/snapshots/test_binary_sensor.ambr +++ b/tests/components/totalconnect/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -228,6 +232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -280,6 +285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -332,6 +338,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -384,6 +391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -436,6 +444,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -488,6 +497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -540,6 +550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -592,6 +603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -644,6 +656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -696,6 +709,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -748,6 +762,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -800,6 +815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -852,6 +868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -904,6 +921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -956,6 +974,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1008,6 +1027,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1060,6 +1080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1112,6 +1133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1164,6 +1186,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1216,6 +1239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1268,6 +1292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1320,6 +1345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1372,6 +1398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1424,6 +1451,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1476,6 +1504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1528,6 +1557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1580,6 +1610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1632,6 +1663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1684,6 +1716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1736,6 +1769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1788,6 +1822,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1840,6 +1875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1892,6 +1928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1944,6 +1981,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1996,6 +2034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2048,6 +2087,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2100,6 +2140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2152,6 +2193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2204,6 +2246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2256,6 +2299,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2308,6 +2352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2360,6 +2405,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2412,6 +2458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2464,6 +2511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2516,6 +2564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2568,6 +2617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2620,6 +2670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2672,6 +2723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2724,6 +2776,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2776,6 +2829,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2828,6 +2882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -2880,6 +2935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2932,6 +2988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -2984,6 +3041,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3036,6 +3094,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3088,6 +3147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -3140,6 +3200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3192,6 +3253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3244,6 +3306,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -3296,6 +3359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3348,6 +3412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3400,6 +3465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -3452,6 +3518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3502,6 +3569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ }), 'original_device_class': , @@ -3552,6 +3620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Police emergency', 'options': dict({ }), 'original_device_class': None, @@ -3601,6 +3670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -3651,6 +3721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -3701,6 +3772,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -3751,6 +3823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3803,6 +3876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3855,6 +3929,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -3907,6 +3982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -3959,6 +4035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4011,6 +4088,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -4063,6 +4141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -4115,6 +4194,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4167,6 +4247,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -4219,6 +4300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -4271,6 +4353,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4323,6 +4406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -4375,6 +4459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -4427,6 +4512,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4479,6 +4565,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -4531,6 +4618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -4583,6 +4671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4635,6 +4724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -4687,6 +4777,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -4739,6 +4830,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -4791,6 +4883,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/totalconnect/snapshots/test_button.ambr b/tests/components/totalconnect/snapshots/test_button.ambr index db90af349cb..09955938eca 100644 --- a/tests/components/totalconnect/snapshots/test_button.ambr +++ b/tests/components/totalconnect/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, @@ -692,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass all', 'options': dict({ }), 'original_device_class': None, @@ -740,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clear bypass', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bypass', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_binary_sensor.ambr b/tests/components/tplink/snapshots/test_binary_sensor.ambr index ed5f935f286..0568ab01e4c 100644 --- a/tests/components/tplink/snapshots/test_binary_sensor.ambr +++ b/tests/components/tplink/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -55,6 +56,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloud connection', 'options': dict({ }), 'original_device_class': , @@ -104,6 +106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -153,6 +156,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity warning', 'options': dict({ }), 'original_device_class': None, @@ -188,6 +192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , @@ -237,6 +242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -286,6 +292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overheated', 'options': dict({ }), 'original_device_class': , @@ -335,6 +342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Overloaded', 'options': dict({ }), 'original_device_class': , @@ -384,6 +392,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature warning', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_button.ambr b/tests/components/tplink/snapshots/test_button.ambr index 37cfb4a36c0..95447bade06 100644 --- a/tests/components/tplink/snapshots/test_button.ambr +++ b/tests/components/tplink/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pair new device', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pan left', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pan right', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset charging contacts consumable', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter consumable', 'options': dict({ }), 'original_device_class': None, @@ -234,6 +239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset main brush consumable', 'options': dict({ }), 'original_device_class': None, @@ -269,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset sensor consumable', 'options': dict({ }), 'original_device_class': None, @@ -304,6 +311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset side brush consumable', 'options': dict({ }), 'original_device_class': None, @@ -339,6 +347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , @@ -374,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop alarm', 'options': dict({ }), 'original_device_class': None, @@ -381,7 +391,7 @@ 'original_name': 'Stop alarm', 'platform': 'tplink', 'previous_unique_id': None, - 'suggested_object_id': 'my_device_stop_alarm', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'stop_alarm', 'unique_id': '123456789ABCDEFGH_stop_alarm', @@ -422,6 +432,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test alarm', 'options': dict({ }), 'original_device_class': None, @@ -429,7 +440,7 @@ 'original_name': 'Test alarm', 'platform': 'tplink', 'previous_unique_id': None, - 'suggested_object_id': 'my_device_test_alarm', + 'suggested_object_id': None, 'supported_features': 0, 'translation_key': 'test_alarm', 'unique_id': '123456789ABCDEFGH_test_alarm', @@ -470,6 +481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tilt down', 'options': dict({ }), 'original_device_class': None, @@ -518,6 +530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tilt up', 'options': dict({ }), 'original_device_class': None, @@ -566,6 +579,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Unpair device', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_camera.ambr b/tests/components/tplink/snapshots/test_camera.ambr index b17b30bbbb4..5a53afff938 100644 --- a/tests/components/tplink/snapshots/test_camera.ambr +++ b/tests/components/tplink/snapshots/test_camera.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Live view', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_climate.ambr b/tests/components/tplink/snapshots/test_climate.ambr index 01738bff943..fedde1e7f08 100644 --- a/tests/components/tplink/snapshots/test_climate.ambr +++ b/tests/components/tplink/snapshots/test_climate.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_fan.ambr b/tests/components/tplink/snapshots/test_fan.ambr index b48ef8d336b..93894f639e8 100644 --- a/tests/components/tplink/snapshots/test_fan.ambr +++ b/tests/components/tplink/snapshots/test_fan.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -77,6 +78,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'my_fan_0', 'options': dict({ }), 'original_device_class': None, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'my_fan_1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_number.ambr b/tests/components/tplink/snapshots/test_number.ambr index 62e44a8abae..eecf7af0d8c 100644 --- a/tests/components/tplink/snapshots/test_number.ambr +++ b/tests/components/tplink/snapshots/test_number.ambr @@ -60,6 +60,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clean count', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pan degrees', 'options': dict({ }), 'original_device_class': None, @@ -174,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power protection', 'options': dict({ }), 'original_device_class': None, @@ -231,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smooth off', 'options': dict({ }), 'original_device_class': None, @@ -288,6 +292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smooth on', 'options': dict({ }), 'original_device_class': None, @@ -345,6 +350,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature offset', 'options': dict({ }), 'original_device_class': , @@ -403,6 +409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tilt degrees', 'options': dict({ }), 'original_device_class': None, @@ -460,6 +467,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn off in', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_select.ambr b/tests/components/tplink/snapshots/test_select.ambr index 1db6e3cf57d..217ab59c469 100644 --- a/tests/components/tplink/snapshots/test_select.ambr +++ b/tests/components/tplink/snapshots/test_select.ambr @@ -77,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm sound', 'options': dict({ }), 'original_device_class': None, @@ -152,6 +153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm volume', 'options': dict({ }), 'original_device_class': None, @@ -211,6 +213,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light preset', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_sensor.ambr b/tests/components/tplink/snapshots/test_sensor.ambr index 05d645552bb..3e145ccec30 100644 --- a/tests/components/tplink/snapshots/test_sensor.ambr +++ b/tests/components/tplink/snapshots/test_sensor.ambr @@ -55,6 +55,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm source', 'options': dict({ }), 'original_device_class': None, @@ -90,6 +91,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-off at', 'options': dict({ }), 'original_device_class': , @@ -141,6 +143,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -192,6 +195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging contacts remaining', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -230,6 +234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging contacts used', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning area', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -329,6 +335,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning progress', 'options': dict({ }), 'original_device_class': None, @@ -364,6 +371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -422,6 +430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -478,6 +487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -532,6 +542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device time', 'options': dict({ }), 'original_device_class': , @@ -582,6 +593,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Error', 'options': dict({ }), 'original_device_class': , @@ -645,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter remaining', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -683,6 +696,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter used', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -723,6 +737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -774,6 +789,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last clean start', 'options': dict({ }), 'original_device_class': , @@ -809,6 +825,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last cleaned area', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -849,6 +866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last cleaned time', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -887,6 +905,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last water leak alert', 'options': dict({ }), 'original_device_class': , @@ -936,6 +955,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush remaining', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -974,6 +994,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main brush used', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1012,6 +1033,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'On since', 'options': dict({ }), 'original_device_class': , @@ -1047,6 +1069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Report interval', 'options': dict({ }), 'original_device_class': , @@ -1082,6 +1105,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor remaining', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1120,6 +1144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensor used', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1158,6 +1183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush remaining', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1196,6 +1222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush used', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1236,6 +1263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal level', 'options': dict({ }), 'original_device_class': None, @@ -1287,6 +1315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1322,6 +1351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SSID', 'options': dict({ }), 'original_device_class': None, @@ -1359,6 +1389,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': , @@ -1396,6 +1427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "This month's consumption", 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1452,6 +1484,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': "Today's consumption", 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1508,6 +1541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning area', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1548,6 +1582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning count', 'options': dict({ }), 'original_device_class': None, @@ -1585,6 +1620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning time', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': , @@ -1625,6 +1661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1681,6 +1718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/tplink/snapshots/test_siren.ambr b/tests/components/tplink/snapshots/test_siren.ambr index 45bad203bc9..37ab2d99a7a 100644 --- a/tests/components/tplink/snapshots/test_siren.ambr +++ b/tests/components/tplink/snapshots/test_siren.ambr @@ -60,6 +60,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_switch.ambr b/tests/components/tplink/snapshots/test_switch.ambr index 6d1d2fa3bad..3b5a3d9f270 100644 --- a/tests/components/tplink/snapshots/test_switch.ambr +++ b/tests/components/tplink/snapshots/test_switch.ambr @@ -55,6 +55,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -103,6 +104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-off enabled', 'options': dict({ }), 'original_device_class': None, @@ -151,6 +153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto-update enabled', 'options': dict({ }), 'original_device_class': None, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Baby cry detection', 'options': dict({ }), 'original_device_class': None, @@ -247,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carpet boost', 'options': dict({ }), 'original_device_class': None, @@ -295,6 +300,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -343,6 +349,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fan sleep mode', 'options': dict({ }), 'original_device_class': None, @@ -391,6 +398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED', 'options': dict({ }), 'original_device_class': None, @@ -439,6 +447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection', 'options': dict({ }), 'original_device_class': None, @@ -487,6 +496,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion sensor', 'options': dict({ }), 'original_device_class': None, @@ -535,6 +545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Person detection', 'options': dict({ }), 'original_device_class': None, @@ -583,6 +594,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smooth transitions', 'options': dict({ }), 'original_device_class': None, @@ -631,6 +643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper detection', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink/snapshots/test_vacuum.ambr b/tests/components/tplink/snapshots/test_vacuum.ambr index e3a7f1d95fe..36847591908 100644 --- a/tests/components/tplink/snapshots/test_vacuum.ambr +++ b/tests/components/tplink/snapshots/test_vacuum.ambr @@ -60,6 +60,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink_omada/snapshots/test_binary_sensor.ambr b/tests/components/tplink_omada/snapshots/test_binary_sensor.ambr index f5ad359c141..3261164f684 100644 --- a/tests/components/tplink_omada/snapshots/test_binary_sensor.ambr +++ b/tests/components/tplink_omada/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 10 LAN status', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 10 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 11 LAN status', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 11 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 12 LAN status', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 12 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 LAN status', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2 LAN status', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4 Internet link', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4 online detection', 'options': dict({ }), 'original_device_class': , @@ -510,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 5 LAN status', 'options': dict({ }), 'original_device_class': , @@ -559,6 +570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 5 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -608,6 +620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 6 LAN status', 'options': dict({ }), 'original_device_class': , @@ -657,6 +670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 6 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -706,6 +720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 7 LAN status', 'options': dict({ }), 'original_device_class': , @@ -755,6 +770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 7 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -804,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 8 LAN status', 'options': dict({ }), 'original_device_class': , @@ -853,6 +870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 8 PoE delivery', 'options': dict({ }), 'original_device_class': , @@ -902,6 +920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 9 LAN status', 'options': dict({ }), 'original_device_class': , @@ -951,6 +970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 9 PoE delivery', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tplink_omada/snapshots/test_sensor.ambr b/tests/components/tplink_omada/snapshots/test_sensor.ambr index dde4c4b8e7a..403babfa1ad 100644 --- a/tests/components/tplink_omada/snapshots/test_sensor.ambr +++ b/tests/components/tplink_omada/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage', 'options': dict({ }), 'original_device_class': None, @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device status', 'options': dict({ }), 'original_device_class': , @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ }), 'original_device_class': None, @@ -194,6 +197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage', 'options': dict({ }), 'original_device_class': None, @@ -254,6 +258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device status', 'options': dict({ }), 'original_device_class': , @@ -314,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tplink_omada/snapshots/test_switch.ambr b/tests/components/tplink_omada/snapshots/test_switch.ambr index 513173248f0..32f2fd1213a 100644 --- a/tests/components/tplink_omada/snapshots/test_switch.ambr +++ b/tests/components/tplink_omada/snapshots/test_switch.ambr @@ -85,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 PoE', 'options': dict({ }), 'original_device_class': None, @@ -133,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2 (Renamed Port) PoE', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/trace/conftest.py b/tests/components/trace/conftest.py deleted file mode 100644 index 01dc57a9948..00000000000 --- a/tests/components/trace/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Conftest for trace tests.""" - -import pytest - - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" diff --git a/tests/components/tractive/snapshots/test_binary_sensor.ambr b/tests/components/tractive/snapshots/test_binary_sensor.ambr index 150318cc753..0a8e796be39 100644 --- a/tests/components/tractive/snapshots/test_binary_sensor.ambr +++ b/tests/components/tractive/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker battery charging', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker power saving', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tractive/snapshots/test_device_tracker.ambr b/tests/components/tractive/snapshots/test_device_tracker.ambr index ca8a4b6d48b..068dc6f04e8 100644 --- a/tests/components/tractive/snapshots/test_device_tracker.ambr +++ b/tests/components/tractive/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tractive/snapshots/test_sensor.ambr b/tests/components/tractive/snapshots/test_sensor.ambr index af4222486b1..158f08ba887 100644 --- a/tests/components/tractive/snapshots/test_sensor.ambr +++ b/tests/components/tractive/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activity', 'options': dict({ }), 'original_device_class': , @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activity time', 'options': dict({ }), 'original_device_class': None, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calories burned', 'options': dict({ }), 'original_device_class': None, @@ -184,6 +187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daily goal', 'options': dict({ }), 'original_device_class': None, @@ -235,6 +239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Day sleep', 'options': dict({ }), 'original_device_class': None, @@ -287,6 +292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night sleep', 'options': dict({ }), 'original_device_class': None, @@ -339,6 +345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rest time', 'options': dict({ }), 'original_device_class': None, @@ -395,6 +402,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep', 'options': dict({ }), 'original_device_class': , @@ -449,6 +457,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker battery', 'options': dict({ }), 'original_device_class': , @@ -507,6 +516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker state', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tractive/snapshots/test_switch.ambr b/tests/components/tractive/snapshots/test_switch.ambr index f83436e9a60..e794dd33aea 100644 --- a/tests/components/tractive/snapshots/test_switch.ambr +++ b/tests/components/tractive/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Live tracking', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker buzzer', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tracker LED', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/transmission/snapshots/test_sensor.ambr b/tests/components/transmission/snapshots/test_sensor.ambr index 71d25e4a520..26e5488f4ca 100644 --- a/tests/components/transmission/snapshots/test_sensor.ambr +++ b/tests/components/transmission/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active torrents', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Completed torrents', 'options': dict({ }), 'original_device_class': None, @@ -122,6 +124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Download speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Paused torrents', 'options': dict({ }), 'original_device_class': None, @@ -229,6 +233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Started torrents', 'options': dict({ }), 'original_device_class': None, @@ -287,6 +292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -342,6 +348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total torrents', 'options': dict({ }), 'original_device_class': None, @@ -393,6 +400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upload speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/transmission/snapshots/test_switch.ambr b/tests/components/transmission/snapshots/test_switch.ambr index 48c342e5acc..038d5e098d4 100644 --- a/tests/components/transmission/snapshots/test_switch.ambr +++ b/tests/components/transmission/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turtle mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/fixtures/dj_k3okx0w3bsgmindp.json b/tests/components/tuya/fixtures/dj_k3okx0w3bsgmindp.json new file mode 100644 index 00000000000..c7922d14436 --- /dev/null +++ b/tests/components/tuya/fixtures/dj_k3okx0w3bsgmindp.json @@ -0,0 +1,921 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Portal Casa Carro Jalimy", + "category": "dj", + "product_id": "k3okx0w3bsgmindp", + "product_name": "Smart Bulb", + "online": false, + "sub": false, + "time_zone": "-03:00", + "active_time": "2024-01-10T13:53:29+00:00", + "create_time": "2024-01-10T13:53:29+00:00", + "update_time": "2024-01-10T13:53:29+00:00", + "function": { + "switch_led": { + "type": "Boolean", + "value": {} + }, + "work_mode": { + "type": "Enum", + "value": { + "range": ["white", "colour", "scene", "music"] + } + }, + "bright_value_v2": { + "type": "Integer", + "value": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "temp_value_v2": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "colour_data_v2": { + "type": "Json", + "value": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "scene_data_v2": { + "type": "Json", + "value": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + } + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "music_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "control_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "rhythm_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "sleep_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "wakeup_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "power_memory": { + "type": "Raw", + "value": {} + }, + "do_not_disturb": { + "type": "Boolean", + "value": {} + }, + "cycle_timing": { + "type": "Raw", + "value": {} + }, + "random_timing": { + "type": "Raw", + "value": {} + } + }, + "status_range": { + "switch_led": { + "type": "Boolean", + "value": {} + }, + "work_mode": { + "type": "Enum", + "value": { + "range": ["white", "colour", "scene", "music"] + } + }, + "bright_value_v2": { + "type": "Integer", + "value": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "temp_value_v2": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "colour_data_v2": { + "type": "Json", + "value": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "scene_data_v2": { + "type": "Json", + "value": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + } + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "music_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "control_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "rhythm_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "sleep_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "wakeup_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "power_memory": { + "type": "Raw", + "value": {} + }, + "do_not_disturb": { + "type": "Boolean", + "value": {} + }, + "cycle_timing": { + "type": "Raw", + "value": {} + }, + "random_timing": { + "type": "Raw", + "value": {} + } + }, + "status": { + "switch_led": true, + "work_mode": "white", + "bright_value_v2": 1000, + "temp_value_v2": 1000, + "colour_data_v2": "{\"h\":0,\"s\":1000,\"v\":1000}", + "scene_data_v2": "{\"scene_num\":1,\"scene_units\":[{\"bright\":200,\"h\":0,\"s\":0,\"temperature\":0,\"unit_change_mode\":\"static\",\"unit_gradient_duration\":13,\"unit_switch_duration\":14,\"v\":0}]}", + "countdown_1": 0, + "music_data": "", + "control_data": "", + "rhythm_mode": "AAAAAAA=", + "sleep_mode": "AAA=", + "wakeup_mode": "AAA=", + "power_memory": "AAEAAAPoA+gD6APo", + "do_not_disturb": false, + "cycle_timing": "AAAA", + "random_timing": "AAAA" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "20": { + "value_convert": "default", + "status_code": "switch_led", + "config_item": { + "statusFormat": { + "switch_led": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "21": { + "value_convert": "default", + "status_code": "work_mode", + "config_item": { + "statusFormat": { + "work_mode": "$" + }, + "valueDesc": { + "range": ["white", "colour", "scene", "music"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "22": { + "value_convert": "default", + "status_code": "bright_value_v2", + "config_item": { + "statusFormat": { + "bright_value_v2": "$" + }, + "valueDesc": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "23": { + "value_convert": "default", + "status_code": "temp_value_v2", + "config_item": { + "statusFormat": { + "temp_value_v2": "$" + }, + "valueDesc": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "24": { + "value_convert": "dj_v2_color_alg", + "status_code": "colour_data_v2", + "config_item": { + "statusFormat": { + "colour_data_v2": "$" + }, + "valueDesc": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "25": { + "value_convert": "dj_v2_scene_alg", + "status_code": "scene_data_v2", + "config_item": { + "statusFormat": { + "scene_data_v2": "$" + }, + "valueDesc": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "26": { + "value_convert": "default", + "status_code": "countdown_1", + "config_item": { + "statusFormat": { + "countdown_1": "$" + }, + "valueDesc": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "27": { + "value_convert": "dj_v2_music_alg", + "status_code": "music_data", + "config_item": { + "statusFormat": { + "music_data": "$" + }, + "valueDesc": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "28": { + "value_convert": "dj_v2_contr_alg", + "status_code": "control_data", + "config_item": { + "statusFormat": { + "control_data": "$" + }, + "valueDesc": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "30": { + "value_convert": "default", + "status_code": "rhythm_mode", + "config_item": { + "statusFormat": { + "rhythm_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "31": { + "value_convert": "default", + "status_code": "sleep_mode", + "config_item": { + "statusFormat": { + "sleep_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "32": { + "value_convert": "default", + "status_code": "wakeup_mode", + "config_item": { + "statusFormat": { + "wakeup_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "33": { + "value_convert": "default", + "status_code": "power_memory", + "config_item": { + "statusFormat": { + "power_memory": "$" + }, + "valueDesc": {}, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "34": { + "value_convert": "default", + "status_code": "do_not_disturb", + "config_item": { + "statusFormat": { + "do_not_disturb": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "209": { + "value_convert": "default", + "status_code": "cycle_timing", + "config_item": { + "statusFormat": { + "cycle_timing": "$" + }, + "valueDesc": {}, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + }, + "210": { + "value_convert": "default", + "status_code": "random_timing", + "config_item": { + "statusFormat": { + "random_timing": "$" + }, + "valueDesc": {}, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "k3okx0w3bsgmindp" + } + } + } +} diff --git a/tests/components/tuya/fixtures/dj_oj4fqh3fo3obgu6a.json b/tests/components/tuya/fixtures/dj_oj4fqh3fo3obgu6a.json new file mode 100644 index 00000000000..12b4f0c885b --- /dev/null +++ b/tests/components/tuya/fixtures/dj_oj4fqh3fo3obgu6a.json @@ -0,0 +1,830 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "L├ímpara Ati", + "category": "dj", + "product_id": "oj4fqh3fo3obgu6a", + "product_name": "Lampada Wi-Fi+bluetooth", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-11-24T23:54:50+00:00", + "create_time": "2025-11-24T23:54:50+00:00", + "update_time": "2025-11-24T23:54:50+00:00", + "function": { + "switch_led": { + "type": "Boolean", + "value": {} + }, + "work_mode": { + "type": "Enum", + "value": { + "range": ["white", "colour", "scene", "music"] + } + }, + "bright_value_v2": { + "type": "Integer", + "value": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "temp_value_v2": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "colour_data_v2": { + "type": "Json", + "value": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "scene_data_v2": { + "type": "Json", + "value": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + } + }, + "countdown_1": { + "type": "Integer", + "value": { + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "music_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "control_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "rhythm_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "sleep_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "wakeup_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + } + }, + "status_range": { + "switch_led": { + "type": "Boolean", + "value": {} + }, + "work_mode": { + "type": "Enum", + "value": { + "range": ["white", "colour", "scene", "music"] + } + }, + "bright_value_v2": { + "type": "Integer", + "value": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "temp_value_v2": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "colour_data_v2": { + "type": "Json", + "value": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "scene_data_v2": { + "type": "Json", + "value": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + } + }, + "countdown_1": { + "type": "Integer", + "value": { + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "music_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "control_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "rhythm_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "sleep_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "wakeup_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + } + }, + "status": { + "switch_led": false, + "work_mode": "white", + "bright_value_v2": 10, + "temp_value_v2": 0, + "colour_data_v2": "{\"h\":0,\"s\":1000,\"v\":1000}", + "scene_data_v2": "{\"scene_num\":1,\"scene_units\":[{\"bright\":200,\"h\":0,\"s\":0,\"temperature\":0,\"unit_change_mode\":\"static\",\"unit_gradient_duration\":13,\"unit_switch_duration\":14,\"v\":0}]}", + "countdown_1": 0, + "music_data": "", + "control_data": "", + "rhythm_mode": "AAAAAAA=", + "sleep_mode": "AAA=", + "wakeup_mode": "AAA=" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "20": { + "value_convert": "default", + "status_code": "switch_led", + "config_item": { + "statusFormat": { + "switch_led": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "21": { + "value_convert": "default", + "status_code": "work_mode", + "config_item": { + "statusFormat": { + "work_mode": "$" + }, + "valueDesc": { + "range": ["white", "colour", "scene", "music"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "22": { + "value_convert": "default", + "status_code": "bright_value_v2", + "config_item": { + "statusFormat": { + "bright_value_v2": "$" + }, + "valueDesc": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "23": { + "value_convert": "default", + "status_code": "temp_value_v2", + "config_item": { + "statusFormat": { + "temp_value_v2": "$" + }, + "valueDesc": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "24": { + "value_convert": "dj_v2_color_alg", + "status_code": "colour_data_v2", + "config_item": { + "statusFormat": { + "colour_data_v2": "$" + }, + "valueDesc": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "25": { + "value_convert": "dj_v2_scene_alg", + "status_code": "scene_data_v2", + "config_item": { + "statusFormat": { + "scene_data_v2": "$" + }, + "valueDesc": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "26": { + "value_convert": "default", + "status_code": "countdown_1", + "config_item": { + "statusFormat": { + "countdown_1": "$" + }, + "valueDesc": { + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "27": { + "value_convert": "dj_v2_music_alg", + "status_code": "music_data", + "config_item": { + "statusFormat": { + "music_data": "$" + }, + "valueDesc": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "28": { + "value_convert": "dj_v2_contr_alg", + "status_code": "control_data", + "config_item": { + "statusFormat": { + "control_data": "$" + }, + "valueDesc": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "30": { + "value_convert": "default", + "status_code": "rhythm_mode", + "config_item": { + "statusFormat": { + "rhythm_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "31": { + "value_convert": "default", + "status_code": "sleep_mode", + "config_item": { + "statusFormat": { + "sleep_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + }, + "32": { + "value_convert": "default", + "status_code": "wakeup_mode", + "config_item": { + "statusFormat": { + "wakeup_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "oj4fqh3fo3obgu6a" + } + } + } +} diff --git a/tests/components/tuya/fixtures/dj_p06rbu0a9jp37ixo.json b/tests/components/tuya/fixtures/dj_p06rbu0a9jp37ixo.json new file mode 100644 index 00000000000..de35bdd6b08 --- /dev/null +++ b/tests/components/tuya/fixtures/dj_p06rbu0a9jp37ixo.json @@ -0,0 +1,899 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Jardim Casa", + "category": "dj", + "product_id": "p06rbu0a9jp37ixo", + "product_name": "JRBULB", + "online": false, + "sub": false, + "time_zone": "-03:00", + "active_time": "2023-11-25T21:45:12+00:00", + "create_time": "2023-11-25T21:45:12+00:00", + "update_time": "2023-11-25T21:45:12+00:00", + "function": { + "switch_led": { + "type": "Boolean", + "value": {} + }, + "work_mode": { + "type": "Enum", + "value": { + "range": ["white", "colour", "scene", "music"] + } + }, + "bright_value_v2": { + "type": "Integer", + "value": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "temp_value_v2": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "colour_data_v2": { + "type": "Json", + "value": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "scene_data_v2": { + "type": "Json", + "value": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + } + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "music_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "control_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "rhythm_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "sleep_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "wakeup_mode": { + "type": "Raw", + "value": { + "maxlen": 255 + } + }, + "power_memory": { + "type": "Raw", + "value": {} + }, + "do_not_disturb": { + "type": "Boolean", + "value": {} + }, + "remote_switch": { + "type": "Boolean", + "value": {} + } + }, + "status_range": { + "switch_led": { + "type": "Boolean", + "value": {} + }, + "work_mode": { + "type": "Enum", + "value": { + "range": ["white", "colour", "scene", "music"] + } + }, + "bright_value_v2": { + "type": "Integer", + "value": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "temp_value_v2": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "colour_data_v2": { + "type": "Json", + "value": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "scene_data_v2": { + "type": "Json", + "value": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + } + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "music_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "control_data": { + "type": "Json", + "value": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + } + }, + "rhythm_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "sleep_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "wakeup_mode": { + "type": "Raw", + "value": { + "maxlen": "255" + } + }, + "power_memory": { + "type": "Raw", + "value": {} + }, + "do_not_disturb": { + "type": "Boolean", + "value": {} + }, + "remote_switch": { + "type": "Boolean", + "value": {} + } + }, + "status": { + "switch_led": true, + "work_mode": "white", + "bright_value_v2": 1000, + "temp_value_v2": 1000, + "colour_data_v2": "{\"h\":0,\"s\":1000,\"v\":1000}", + "scene_data_v2": "{\"scene_num\":1,\"scene_units\":[{\"bright\":200,\"h\":0,\"s\":0,\"temperature\":0,\"unit_change_mode\":\"static\",\"unit_gradient_duration\":13,\"unit_switch_duration\":14,\"v\":0}]}", + "countdown_1": 0, + "music_data": "", + "control_data": "", + "rhythm_mode": "AAAAAAA=", + "sleep_mode": "AAA=", + "wakeup_mode": "AAA=", + "power_memory": "AAEAAAPoA+gD6APo", + "do_not_disturb": false, + "remote_switch": true + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "20": { + "value_convert": "default", + "status_code": "switch_led", + "config_item": { + "statusFormat": { + "switch_led": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "21": { + "value_convert": "default", + "status_code": "work_mode", + "config_item": { + "statusFormat": { + "work_mode": "$" + }, + "valueDesc": { + "range": ["white", "colour", "scene", "music"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "22": { + "value_convert": "default", + "status_code": "bright_value_v2", + "config_item": { + "statusFormat": { + "bright_value_v2": "$" + }, + "valueDesc": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "23": { + "value_convert": "default", + "status_code": "temp_value_v2", + "config_item": { + "statusFormat": { + "temp_value_v2": "$" + }, + "valueDesc": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "24": { + "value_convert": "dj_v2_color_alg", + "status_code": "colour_data_v2", + "config_item": { + "statusFormat": { + "colour_data_v2": "$" + }, + "valueDesc": { + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "25": { + "value_convert": "dj_v2_scene_alg", + "status_code": "scene_data_v2", + "config_item": { + "statusFormat": { + "scene_data_v2": "$" + }, + "valueDesc": { + "scene_num": { + "min": 1, + "scale": 0, + "max": 8, + "step": 1 + }, + "scene_units": { + "unit_change_mode": { + "range": ["static", "jump", "gradient"] + }, + "unit_switch_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "unit_gradient_duration": { + "min": 0, + "scale": 0, + "max": 100, + "step": 1 + }, + "bright": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + } + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "26": { + "value_convert": "default", + "status_code": "countdown_1", + "config_item": { + "statusFormat": { + "countdown_1": "$" + }, + "valueDesc": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "27": { + "value_convert": "dj_v2_music_alg", + "status_code": "music_data", + "config_item": { + "statusFormat": { + "music_data": "$" + }, + "valueDesc": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "28": { + "value_convert": "dj_v2_contr_alg", + "status_code": "control_data", + "config_item": { + "statusFormat": { + "control_data": "$" + }, + "valueDesc": { + "change_mode": { + "range": ["direct", "gradient"] + }, + "bright": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "temperature": { + "min": 0, + "scale": 0, + "unit": "", + "max": 1000, + "step": 1 + }, + "h": { + "min": 0, + "scale": 0, + "unit": "", + "max": 360, + "step": 1 + }, + "s": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + }, + "v": { + "min": 0, + "scale": 0, + "unit": "", + "max": 255, + "step": 1 + } + }, + "valueType": "Json", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "30": { + "value_convert": "default", + "status_code": "rhythm_mode", + "config_item": { + "statusFormat": { + "rhythm_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "31": { + "value_convert": "default", + "status_code": "sleep_mode", + "config_item": { + "statusFormat": { + "sleep_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "32": { + "value_convert": "default", + "status_code": "wakeup_mode", + "config_item": { + "statusFormat": { + "wakeup_mode": "$" + }, + "valueDesc": { + "maxlen": "255" + }, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "33": { + "value_convert": "default", + "status_code": "power_memory", + "config_item": { + "statusFormat": { + "power_memory": "$" + }, + "valueDesc": {}, + "valueType": "Raw", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "34": { + "value_convert": "default", + "status_code": "do_not_disturb", + "config_item": { + "statusFormat": { + "do_not_disturb": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + }, + "41": { + "value_convert": "default", + "status_code": "remote_switch", + "config_item": { + "statusFormat": { + "remote_switch": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "p06rbu0a9jp37ixo" + } + } + } +} diff --git a/tests/components/tuya/fixtures/hjjcy_9f8pjxsmaqnk2tzr.json b/tests/components/tuya/fixtures/hjjcy_9f8pjxsmaqnk2tzr.json new file mode 100644 index 00000000000..e5ff96a8dd1 --- /dev/null +++ b/tests/components/tuya/fixtures/hjjcy_9f8pjxsmaqnk2tzr.json @@ -0,0 +1,334 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "MT15/MT29", + "category": "hjjcy", + "product_id": "9f8pjxsmaqnk2tzr", + "product_name": "MT15/MT29", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-11-16T00:36:54+00:00", + "create_time": "2025-11-16T00:36:54+00:00", + "update_time": "2025-11-16T00:36:54+00:00", + "function": { + "alarm_volume": { + "type": "Enum", + "value": { + "range": ["low", "middle", "high", "mute"] + } + } + }, + "status_range": { + "air_quality_index": { + "type": "Enum", + "value": { + "range": ["level_1", "level_2", "level_3"] + } + }, + "temp_current": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -400, + "max": 2000, + "scale": 0, + "step": 1 + } + }, + "humidity_value": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "co2_value": { + "type": "Integer", + "value": { + "unit": "ppm", + "min": 0, + "max": 10000, + "scale": 0, + "step": 1 + } + }, + "ch2o_value": { + "type": "Integer", + "value": { + "unit": "mg/m┬│", + "min": 0, + "max": 9999, + "scale": 3, + "step": 1 + } + }, + "pm25_value": { + "type": "Integer", + "value": { + "unit": "ug/m┬│", + "min": 0, + "max": 999, + "scale": 0, + "step": 1 + } + }, + "pm1": { + "type": "Integer", + "value": { + "unit": "ug/m┬│", + "min": 0, + "max": 999, + "scale": 0, + "step": 1 + } + }, + "pm10": { + "type": "Integer", + "value": { + "unit": "ug/m┬│", + "min": 0, + "max": 999, + "scale": 0, + "step": 1 + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "charge_state": { + "type": "Boolean", + "value": {} + }, + "alarm_volume": { + "type": "Enum", + "value": { + "range": ["low", "middle", "high", "mute"] + } + } + }, + "status": { + "air_quality_index": "level_1", + "temp_current": 27, + "humidity_value": 68, + "co2_value": 439, + "ch2o_value": 1, + "pm25_value": 11, + "pm1": 12, + "pm10": 15, + "battery_percentage": 100, + "charge_state": true, + "alarm_volume": "middle" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "air_quality_index", + "config_item": { + "statusFormat": { + "air_quality_index": "$" + }, + "valueDesc": { + "range": ["level_1", "level_2", "level_3"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "2": { + "value_convert": "default", + "status_code": "temp_current", + "config_item": { + "statusFormat": { + "temp_current": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -400, + "max": 2000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "3": { + "value_convert": "default", + "status_code": "humidity_value", + "config_item": { + "statusFormat": { + "humidity_value": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "4": { + "value_convert": "default", + "status_code": "co2_value", + "config_item": { + "statusFormat": { + "co2_value": "$" + }, + "valueDesc": { + "unit": "ppm", + "min": 0, + "max": 10000, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "5": { + "value_convert": "default", + "status_code": "ch2o_value", + "config_item": { + "statusFormat": { + "ch2o_value": "$" + }, + "valueDesc": { + "unit": "mg/m┬│", + "min": 0, + "max": 9999, + "scale": 3, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "7": { + "value_convert": "default", + "status_code": "pm25_value", + "config_item": { + "statusFormat": { + "pm25_value": "$" + }, + "valueDesc": { + "unit": "ug/m┬│", + "min": 0, + "max": 999, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "8": { + "value_convert": "default", + "status_code": "pm1", + "config_item": { + "statusFormat": { + "pm1": "$" + }, + "valueDesc": { + "unit": "ug/m┬│", + "min": 0, + "max": 999, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "9": { + "value_convert": "default", + "status_code": "pm10", + "config_item": { + "statusFormat": { + "pm10": "$" + }, + "valueDesc": { + "unit": "ug/m┬│", + "min": 0, + "max": 999, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "22": { + "value_convert": "default", + "status_code": "battery_percentage", + "config_item": { + "statusFormat": { + "battery_percentage": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "23": { + "value_convert": "default", + "status_code": "charge_state", + "config_item": { + "statusFormat": { + "charge_state": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + }, + "28": { + "value_convert": "default", + "status_code": "alarm_volume", + "config_item": { + "statusFormat": { + "alarm_volume": "$" + }, + "valueDesc": { + "range": ["low", "middle", "high", "mute"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "9f8pjxsmaqnk2tzr" + } + } + } +} diff --git a/tests/components/tuya/fixtures/infrared_ac_47peys.json b/tests/components/tuya/fixtures/infrared_ac_47peys.json new file mode 100644 index 00000000000..1358f4794b5 --- /dev/null +++ b/tests/components/tuya/fixtures/infrared_ac_47peys.json @@ -0,0 +1,96 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Ar", + "category": "infrared_ac", + "product_id": "47peys", + "product_name": "Air Conditioner", + "online": true, + "sub": true, + "time_zone": "-03:00", + "active_time": "2025-11-16T18:17:37+00:00", + "create_time": "2025-11-16T18:17:37+00:00", + "update_time": "2025-11-16T18:17:37+00:00", + "function": { + "F": { + "type": "ENUM", + "value": { + "min": 0, + "max": 3, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "M": { + "type": "ENUM", + "value": { + "min": 0, + "max": 4, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "PowerOff": { + "type": "STRING", + "value": "PowerOff" + }, + "PowerOn": { + "type": "STRING", + "value": "PowerOn" + }, + "T": { + "type": "ENUM", + "value": { + "min": 16, + "max": 30, + "scale": 0, + "step": 1, + "type": "Integer" + } + } + }, + "status_range": { + "wind": { + "type": "ENUM", + "value": { + "min": 0, + "max": 3, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "mode": { + "type": "ENUM", + "value": { + "min": 0, + "max": 4, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "power": { + "type": "BOOLEAN", + "value": {} + }, + "temp": { + "type": "ENUM", + "value": { + "min": 16, + "max": 30, + "scale": 0, + "step": 1, + "type": "Integer" + } + } + }, + "status": {}, + "set_up": false, + "support_local": false, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/infrared_ac_qzktzhehinzsz2je.json b/tests/components/tuya/fixtures/infrared_ac_qzktzhehinzsz2je.json new file mode 100644 index 00000000000..b96be7948bd --- /dev/null +++ b/tests/components/tuya/fixtures/infrared_ac_qzktzhehinzsz2je.json @@ -0,0 +1,96 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Air", + "category": "infrared_ac", + "product_id": "qzktzhehinzsz2je", + "product_name": "Air Conditioning", + "online": false, + "sub": true, + "time_zone": "-03:00", + "active_time": "2025-11-16T23:22:07+00:00", + "create_time": "2025-11-16T23:22:07+00:00", + "update_time": "2025-11-16T23:22:07+00:00", + "function": { + "F": { + "type": "ENUM", + "value": { + "min": 0, + "max": 3, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "M": { + "type": "ENUM", + "value": { + "min": 0, + "max": 4, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "PowerOff": { + "type": "STRING", + "value": "PowerOff" + }, + "PowerOn": { + "type": "STRING", + "value": "PowerOn" + }, + "T": { + "type": "ENUM", + "value": { + "min": 16, + "max": 30, + "scale": 0, + "step": 1, + "type": "Integer" + } + } + }, + "status_range": { + "wind": { + "type": "ENUM", + "value": { + "min": 0, + "max": 3, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "mode": { + "type": "ENUM", + "value": { + "min": 0, + "max": 4, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "power": { + "type": "BOOLEAN", + "value": {} + }, + "temp": { + "type": "ENUM", + "value": { + "min": 16, + "max": 30, + "scale": 0, + "step": 1, + "type": "Integer" + } + } + }, + "status": {}, + "set_up": false, + "support_local": false, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/infrared_tv_47pew0.json b/tests/components/tuya/fixtures/infrared_tv_47pew0.json new file mode 100644 index 00000000000..cb13c420d04 --- /dev/null +++ b/tests/components/tuya/fixtures/infrared_tv_47pew0.json @@ -0,0 +1,129 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "TV", + "category": "infrared_tv", + "product_id": "47pew0", + "product_name": "TV", + "online": true, + "sub": true, + "time_zone": "-03:00", + "active_time": "2025-11-16T18:13:00+00:00", + "create_time": "2025-11-16T18:13:00+00:00", + "update_time": "2025-11-16T18:13:00+00:00", + "function": { + "-/--": { + "type": "STRING", + "value": "-/--" + }, + "0": { + "type": "STRING", + "value": 0 + }, + "1": { + "type": "STRING", + "value": 1 + }, + "2": { + "type": "STRING", + "value": 2 + }, + "3": { + "type": "STRING", + "value": 3 + }, + "4": { + "type": "STRING", + "value": 4 + }, + "5": { + "type": "STRING", + "value": 5 + }, + "6": { + "type": "STRING", + "value": 6 + }, + "7": { + "type": "STRING", + "value": 7 + }, + "8": { + "type": "STRING", + "value": 8 + }, + "9": { + "type": "STRING", + "value": 9 + }, + "Back": { + "type": "STRING", + "value": "Back" + }, + "C": { + "type": "ENUM", + "value": { + "min": 1, + "max": 999, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "Channel+": { + "type": "STRING", + "value": "Channel+" + }, + "Channel-": { + "type": "STRING", + "value": "Channel-" + }, + "Down": { + "type": "STRING", + "value": "Down" + }, + "Home": { + "type": "STRING", + "value": "Home" + }, + "Left": { + "type": "STRING", + "value": "Left" + }, + "Menu": { + "type": "STRING", + "value": "Menu" + }, + "OK": { + "type": "STRING", + "value": "OK" + }, + "Power": { + "type": "STRING", + "value": "Power" + }, + "Right": { + "type": "STRING", + "value": "Right" + }, + "Up": { + "type": "STRING", + "value": "Up" + }, + "Volume+": { + "type": "STRING", + "value": "Volume+" + }, + "Volume-": { + "type": "STRING", + "value": "Volume-" + } + }, + "status_range": {}, + "status": {}, + "set_up": false, + "support_local": false, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/infrared_tv_lplun31mo1xaonwz.json b/tests/components/tuya/fixtures/infrared_tv_lplun31mo1xaonwz.json new file mode 100644 index 00000000000..a5c245617d7 --- /dev/null +++ b/tests/components/tuya/fixtures/infrared_tv_lplun31mo1xaonwz.json @@ -0,0 +1,129 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "TV", + "category": "infrared_tv", + "product_id": "lplun31mo1xaonwz", + "product_name": "TV", + "online": false, + "sub": true, + "time_zone": "-03:00", + "active_time": "2025-11-16T23:20:17+00:00", + "create_time": "2025-11-16T23:20:17+00:00", + "update_time": "2025-11-16T23:20:17+00:00", + "function": { + "-/--": { + "type": "STRING", + "value": "-/--" + }, + "0": { + "type": "STRING", + "value": 0 + }, + "1": { + "type": "STRING", + "value": 1 + }, + "2": { + "type": "STRING", + "value": 2 + }, + "3": { + "type": "STRING", + "value": 3 + }, + "4": { + "type": "STRING", + "value": 4 + }, + "5": { + "type": "STRING", + "value": 5 + }, + "6": { + "type": "STRING", + "value": 6 + }, + "7": { + "type": "STRING", + "value": 7 + }, + "8": { + "type": "STRING", + "value": 8 + }, + "9": { + "type": "STRING", + "value": 9 + }, + "Back": { + "type": "STRING", + "value": "Back" + }, + "C": { + "type": "ENUM", + "value": { + "min": 1, + "max": 999, + "scale": 0, + "step": 1, + "type": "Integer" + } + }, + "Channel+": { + "type": "STRING", + "value": "Channel+" + }, + "Channel-": { + "type": "STRING", + "value": "Channel-" + }, + "Down": { + "type": "STRING", + "value": "Down" + }, + "Home": { + "type": "STRING", + "value": "Home" + }, + "Left": { + "type": "STRING", + "value": "Left" + }, + "Menu": { + "type": "STRING", + "value": "Menu" + }, + "OK": { + "type": "STRING", + "value": "OK" + }, + "Power": { + "type": "STRING", + "value": "Power" + }, + "Right": { + "type": "STRING", + "value": "Right" + }, + "Up": { + "type": "STRING", + "value": "Up" + }, + "Volume+": { + "type": "STRING", + "value": "Volume+" + }, + "Volume-": { + "type": "STRING", + "value": "Volume-" + } + }, + "status_range": {}, + "status": {}, + "set_up": false, + "support_local": false, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/pir_o1l76njefmksbgkk.json b/tests/components/tuya/fixtures/pir_o1l76njefmksbgkk.json new file mode 100644 index 00000000000..ddfdaae73e2 --- /dev/null +++ b/tests/components/tuya/fixtures/pir_o1l76njefmksbgkk.json @@ -0,0 +1,77 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "PIR", + "category": "pir", + "product_id": "o1l76njefmksbgkk", + "product_name": "PIR", + "online": false, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-09-27T22:49:06+00:00", + "create_time": "2025-09-27T22:49:06+00:00", + "update_time": "2025-09-27T22:49:06+00:00", + "function": {}, + "status_range": { + "pir": { + "type": "Enum", + "value": { + "range": ["pir", "none"] + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + } + }, + "status": { + "pir": "pir", + "battery_percentage": 100 + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "pir", + "config_item": { + "statusFormat": { + "pir": "$" + }, + "valueDesc": { + "range": ["pir", "none"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "o1l76njefmksbgkk" + } + }, + "4": { + "value_convert": "default", + "status_code": "battery_percentage", + "config_item": { + "statusFormat": { + "battery_percentage": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "o1l76njefmksbgkk" + } + } + } +} diff --git a/tests/components/tuya/fixtures/tdq_1ctrc5jx88mtdh9w.json b/tests/components/tuya/fixtures/tdq_1ctrc5jx88mtdh9w.json new file mode 100644 index 00000000000..f9bd83e3962 --- /dev/null +++ b/tests/components/tuya/fixtures/tdq_1ctrc5jx88mtdh9w.json @@ -0,0 +1,303 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Puerta Casa ", + "category": "tdq", + "product_id": "1ctrc5jx88mtdh9w", + "product_name": "WiFi Breaker", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2023-12-17T14:43:05+00:00", + "create_time": "2023-12-17T14:43:05+00:00", + "update_time": "2023-12-17T14:43:05+00:00", + "function": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "relay_status": { + "type": "Enum", + "value": { + "range": ["0", "1", "2"] + } + }, + "random_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "cycle_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_inching": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_type": { + "type": "Enum", + "value": { + "range": ["flip", "sync", "button"] + } + } + }, + "status_range": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "test_bit": { + "type": "Integer", + "value": { + "min": 0, + "max": 5, + "scale": 0, + "step": 1 + } + }, + "fault": { + "type": "Bitmap", + "value": { + "label": ["ov_cr", "ov_vol", "ov_pwr", "ls_cr", "ls_vol", "ls_pow"] + } + }, + "relay_status": { + "type": "Enum", + "value": { + "range": ["0", "1", "2"] + } + }, + "random_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "cycle_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_inching": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_type": { + "type": "Enum", + "value": { + "range": ["flip", "sync", "button"] + } + } + }, + "status": { + "switch_1": false, + "countdown_1": 0, + "test_bit": 0, + "fault": 0, + "relay_status": "0", + "random_time": "", + "cycle_time": "", + "switch_inching": "AQAB", + "switch_type": "flip" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "switch_1", + "config_item": { + "statusFormat": { + "switch_1": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "9": { + "value_convert": "default", + "status_code": "countdown_1", + "config_item": { + "statusFormat": { + "countdown_1": "$" + }, + "valueDesc": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "24": { + "value_convert": "default", + "status_code": "test_bit", + "config_item": { + "statusFormat": { + "test_bit": "$" + }, + "valueDesc": { + "min": 0, + "max": 5, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "29": { + "value_convert": "default", + "status_code": "fault", + "config_item": { + "statusFormat": { + "fault": "$" + }, + "valueDesc": { + "label": ["ov_cr", "ov_vol", "ov_pwr", "ls_cr", "ls_vol", "ls_pow"] + }, + "valueType": "Bitmap", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "38": { + "value_convert": "enum", + "status_code": "relay_status", + "config_item": { + "statusFormat": { + "relay_status": "$" + }, + "valueDesc": { + "range": ["0", "1", "2"] + }, + "valueType": "Enum", + "enumMappingMap": { + "0": { + "code": "relay_status", + "value": "0" + }, + "1": { + "code": "relay_status", + "value": "1" + }, + "2": { + "code": "relay_status", + "value": "2" + }, + "memory": { + "code": "relay_status", + "value": "2" + }, + "off": { + "code": "relay_status", + "value": "0" + }, + "on": { + "code": "relay_status", + "value": "1" + } + }, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "42": { + "value_convert": "default", + "status_code": "random_time", + "config_item": { + "statusFormat": { + "random_time": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "43": { + "value_convert": "default", + "status_code": "cycle_time", + "config_item": { + "statusFormat": { + "cycle_time": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "44": { + "value_convert": "default", + "status_code": "switch_inching", + "config_item": { + "statusFormat": { + "switch_inching": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + }, + "47": { + "value_convert": "default", + "status_code": "switch_type", + "config_item": { + "statusFormat": { + "switch_type": "$" + }, + "valueDesc": { + "range": ["flip", "sync", "button"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "1ctrc5jx88mtdh9w" + } + } + } +} diff --git a/tests/components/tuya/fixtures/tdq_emb5khohohihmbxc.json b/tests/components/tuya/fixtures/tdq_emb5khohohihmbxc.json new file mode 100644 index 00000000000..7c8a83aee8b --- /dev/null +++ b/tests/components/tuya/fixtures/tdq_emb5khohohihmbxc.json @@ -0,0 +1,303 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Server Fan", + "category": "tdq", + "product_id": "emb5khohohihmbxc", + "product_name": "WiFi Breaker", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2024-01-17T20:15:39+00:00", + "create_time": "2024-01-17T20:15:39+00:00", + "update_time": "2024-01-17T20:15:39+00:00", + "function": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "relay_status": { + "type": "Enum", + "value": { + "range": ["0", "1", "2"] + } + }, + "random_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "cycle_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_inching": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_type": { + "type": "Enum", + "value": { + "range": ["flip", "sync", "button"] + } + } + }, + "status_range": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "test_bit": { + "type": "Integer", + "value": { + "min": 0, + "max": 5, + "scale": 0, + "step": 1 + } + }, + "fault": { + "type": "Bitmap", + "value": { + "label": ["ov_cr", "ov_vol", "ov_pwr", "ls_cr", "ls_vol", "ls_pow"] + } + }, + "relay_status": { + "type": "Enum", + "value": { + "range": ["0", "1", "2"] + } + }, + "random_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "cycle_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_inching": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_type": { + "type": "Enum", + "value": { + "range": ["flip", "sync", "button"] + } + } + }, + "status": { + "switch_1": true, + "countdown_1": 0, + "test_bit": 0, + "fault": 0, + "relay_status": "2", + "random_time": "", + "cycle_time": "", + "switch_inching": "AAAC", + "switch_type": "flip" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "switch_1", + "config_item": { + "statusFormat": { + "switch_1": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "9": { + "value_convert": "default", + "status_code": "countdown_1", + "config_item": { + "statusFormat": { + "countdown_1": "$" + }, + "valueDesc": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "24": { + "value_convert": "default", + "status_code": "test_bit", + "config_item": { + "statusFormat": { + "test_bit": "$" + }, + "valueDesc": { + "min": 0, + "max": 5, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "29": { + "value_convert": "default", + "status_code": "fault", + "config_item": { + "statusFormat": { + "fault": "$" + }, + "valueDesc": { + "label": ["ov_cr", "ov_vol", "ov_pwr", "ls_cr", "ls_vol", "ls_pow"] + }, + "valueType": "Bitmap", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "38": { + "value_convert": "enum", + "status_code": "relay_status", + "config_item": { + "statusFormat": { + "relay_status": "$" + }, + "valueDesc": { + "range": ["0", "1", "2"] + }, + "valueType": "Enum", + "enumMappingMap": { + "0": { + "code": "relay_status", + "value": "0" + }, + "1": { + "code": "relay_status", + "value": "1" + }, + "2": { + "code": "relay_status", + "value": "2" + }, + "memory": { + "code": "relay_status", + "value": "2" + }, + "off": { + "code": "relay_status", + "value": "0" + }, + "on": { + "code": "relay_status", + "value": "1" + } + }, + "pid": "emb5khohohihmbxc" + } + }, + "42": { + "value_convert": "default", + "status_code": "random_time", + "config_item": { + "statusFormat": { + "random_time": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "43": { + "value_convert": "default", + "status_code": "cycle_time", + "config_item": { + "statusFormat": { + "cycle_time": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "44": { + "value_convert": "default", + "status_code": "switch_inching", + "config_item": { + "statusFormat": { + "switch_inching": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + }, + "47": { + "value_convert": "default", + "status_code": "switch_type", + "config_item": { + "statusFormat": { + "switch_type": "$" + }, + "valueDesc": { + "range": ["flip", "sync", "button"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "emb5khohohihmbxc" + } + } + } +} diff --git a/tests/components/tuya/fixtures/tdq_gdknjvdpiwoq6smx.json b/tests/components/tuya/fixtures/tdq_gdknjvdpiwoq6smx.json new file mode 100644 index 00000000000..6ad3f92e8ad --- /dev/null +++ b/tests/components/tuya/fixtures/tdq_gdknjvdpiwoq6smx.json @@ -0,0 +1,253 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Jardim frontal ", + "category": "tdq", + "product_id": "gdknjvdpiwoq6smx", + "product_name": "Smart Switch Module", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2023-05-09T18:26:02+00:00", + "create_time": "2023-05-09T18:26:02+00:00", + "update_time": "2023-05-09T18:26:02+00:00", + "function": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "relay_status": { + "type": "Enum", + "value": { + "range": ["0", "1", "2"] + } + }, + "random_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "cycle_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_inching": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_type": { + "type": "Enum", + "value": { + "range": ["flip", "sync", "button"] + } + } + }, + "status_range": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + } + }, + "relay_status": { + "type": "Enum", + "value": { + "range": ["0", "1", "2"] + } + }, + "random_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "cycle_time": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_inching": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "switch_type": { + "type": "Enum", + "value": { + "range": ["flip", "sync", "button"] + } + } + }, + "status": { + "switch_1": false, + "countdown_1": 0, + "relay_status": "0", + "random_time": "", + "cycle_time": "AX8BaAP8AAEAgg==", + "switch_inching": "", + "switch_type": "flip" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "switch_1", + "config_item": { + "statusFormat": { + "switch_1": "$" + }, + "valueDesc": {}, + "valueType": "Boolean", + "enumMappingMap": {}, + "pid": "gdknjvdpiwoq6smx" + } + }, + "9": { + "value_convert": "default", + "status_code": "countdown_1", + "config_item": { + "statusFormat": { + "countdown_1": "$" + }, + "valueDesc": { + "unit": "s", + "min": 0, + "max": 86400, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "gdknjvdpiwoq6smx" + } + }, + "38": { + "value_convert": "enum", + "status_code": "relay_status", + "config_item": { + "statusFormat": { + "relay_status": "$" + }, + "valueDesc": { + "range": ["0", "1", "2"] + }, + "valueType": "Enum", + "enumMappingMap": { + "0": { + "code": "relay_status", + "value": "0" + }, + "1": { + "code": "relay_status", + "value": "1" + }, + "2": { + "code": "relay_status", + "value": "2" + }, + "memory": { + "code": "relay_status", + "value": "2" + }, + "off": { + "code": "relay_status", + "value": "0" + }, + "on": { + "code": "relay_status", + "value": "1" + } + }, + "pid": "gdknjvdpiwoq6smx" + } + }, + "42": { + "value_convert": "default", + "status_code": "random_time", + "config_item": { + "statusFormat": { + "random_time": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "gdknjvdpiwoq6smx" + } + }, + "43": { + "value_convert": "default", + "status_code": "cycle_time", + "config_item": { + "statusFormat": { + "cycle_time": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "gdknjvdpiwoq6smx" + } + }, + "44": { + "value_convert": "default", + "status_code": "switch_inching", + "config_item": { + "statusFormat": { + "switch_inching": "$" + }, + "valueDesc": { + "maxlen": 255 + }, + "valueType": "String", + "enumMappingMap": {}, + "pid": "gdknjvdpiwoq6smx" + } + }, + "47": { + "value_convert": "default", + "status_code": "switch_type", + "config_item": { + "statusFormat": { + "switch_type": "$" + }, + "valueDesc": { + "range": ["flip", "sync", "button"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "gdknjvdpiwoq6smx" + } + } + } +} diff --git a/tests/components/tuya/fixtures/wnykq_x0lyfgjuguuh1vof.json b/tests/components/tuya/fixtures/wnykq_x0lyfgjuguuh1vof.json new file mode 100644 index 00000000000..3c3631452c2 --- /dev/null +++ b/tests/components/tuya/fixtures/wnykq_x0lyfgjuguuh1vof.json @@ -0,0 +1,22 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Smart IR+RF Remote Control", + "category": "wnykq", + "product_id": "x0lyfgjuguuh1vof", + "product_name": "Smart IR+RF Remote Control", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-11-16T18:05:50+00:00", + "create_time": "2025-11-16T18:05:50+00:00", + "update_time": "2025-11-16T18:05:50+00:00", + "function": {}, + "status_range": {}, + "status": {}, + "set_up": false, + "support_local": true, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/wsdcg_vlzqwckk.json b/tests/components/tuya/fixtures/wsdcg_vlzqwckk.json new file mode 100644 index 00000000000..112da21b9f7 --- /dev/null +++ b/tests/components/tuya/fixtures/wsdcg_vlzqwckk.json @@ -0,0 +1,348 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Temperature Humidity Sensor abelhas pasillo", + "category": "wsdcg", + "product_id": "vlzqwckk", + "product_name": "Temperature Humidity Sensor", + "online": false, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-09-12T01:47:39+00:00", + "create_time": "2025-09-12T01:47:39+00:00", + "update_time": "2025-09-12T01:47:39+00:00", + "function": { + "temp_unit_convert": { + "type": "Enum", + "value": { + "range": ["c", "f"] + } + }, + "maxtemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "minitemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "maxhum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "minihum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + } + }, + "status_range": { + "va_temperature": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "va_humidity": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "temp_unit_convert": { + "type": "Enum", + "value": { + "range": ["c", "f"] + } + }, + "maxtemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "minitemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "maxhum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "minihum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "temp_alarm": { + "type": "Enum", + "value": { + "range": ["loweralarm", "upperalarm", "cancel"] + } + }, + "hum_alarm": { + "type": "Enum", + "value": { + "range": ["loweralarm", "upperalarm", "cancel"] + } + } + }, + "status": { + "va_temperature": 298, + "va_humidity": 45, + "battery_percentage": 100, + "temp_unit_convert": "c", + "maxtemp_set": 390, + "minitemp_set": 0, + "maxhum_set": 60, + "minihum_set": 20, + "temp_alarm": "cancel", + "hum_alarm": "upperalarm" + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "va_temperature", + "config_item": { + "statusFormat": { + "va_temperature": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "2": { + "value_convert": "default", + "status_code": "humidity_value", + "config_item": { + "statusFormat": { + "va_humidity": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "4": { + "value_convert": "default", + "status_code": "battery_percentage", + "config_item": { + "statusFormat": { + "battery_percentage": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "9": { + "value_convert": "default", + "status_code": "temp_unit_convert", + "config_item": { + "statusFormat": { + "temp_unit_convert": "$" + }, + "valueDesc": { + "range": ["c", "f"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "10": { + "value_convert": "default", + "status_code": "maxtemp_set", + "config_item": { + "statusFormat": { + "maxtemp_set": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "11": { + "value_convert": "default", + "status_code": "minitemp_set", + "config_item": { + "statusFormat": { + "minitemp_set": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "12": { + "value_convert": "default", + "status_code": "maxhum_set", + "config_item": { + "statusFormat": { + "maxhum_set": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "13": { + "value_convert": "default", + "status_code": "minihum_set", + "config_item": { + "statusFormat": { + "minihum_set": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "14": { + "value_convert": "default", + "status_code": "temp_alarm", + "config_item": { + "statusFormat": { + "temp_alarm": "$" + }, + "valueDesc": { + "range": ["loweralarm", "upperalarm", "cancel"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + }, + "15": { + "value_convert": "default", + "status_code": "hum_alarm", + "config_item": { + "statusFormat": { + "hum_alarm": "$" + }, + "valueDesc": { + "range": ["loweralarm", "upperalarm", "cancel"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "vlzqwckk" + } + } + } +} diff --git a/tests/components/tuya/fixtures/wsdcg_xflodz7oja0pndk3.json b/tests/components/tuya/fixtures/wsdcg_xflodz7oja0pndk3.json new file mode 100644 index 00000000000..0b01b35204e --- /dev/null +++ b/tests/components/tuya/fixtures/wsdcg_xflodz7oja0pndk3.json @@ -0,0 +1,428 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Sensor T & H Server Home", + "category": "wsdcg", + "product_id": "xflodz7oja0pndk3", + "product_name": "T&H Sensor", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2023-12-14T21:05:25+00:00", + "create_time": "2023-12-14T21:05:25+00:00", + "update_time": "2023-12-14T21:05:25+00:00", + "function": { + "temp_unit_convert": { + "type": "Enum", + "value": { + "range": ["c", "f"] + } + }, + "maxtemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "minitemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "maxhum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "minihum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "temp_sensitivity": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": 3, + "max": 20, + "scale": 1, + "step": 1 + } + }, + "hum_sensitivity": { + "type": "Integer", + "value": { + "unit": "%", + "min": 3, + "max": 20, + "scale": 0, + "step": 1 + } + } + }, + "status_range": { + "va_temperature": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "va_humidity": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "temp_unit_convert": { + "type": "Enum", + "value": { + "range": ["c", "f"] + } + }, + "maxtemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "minitemp_set": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + } + }, + "maxhum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "minihum_set": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "temp_alarm": { + "type": "Enum", + "value": { + "range": ["loweralarm", "upperalarm", "cancel"] + } + }, + "hum_alarm": { + "type": "Enum", + "value": { + "range": ["loweralarm", "upperalarm", "cancel"] + } + }, + "temp_sensitivity": { + "type": "Integer", + "value": { + "unit": "Ôäâ", + "min": 3, + "max": 20, + "scale": 1, + "step": 1 + } + }, + "hum_sensitivity": { + "type": "Integer", + "value": { + "unit": "%", + "min": 3, + "max": 20, + "scale": 0, + "step": 1 + } + } + }, + "status": { + "va_temperature": 327, + "va_humidity": 50, + "battery_percentage": 100, + "temp_unit_convert": "c", + "maxtemp_set": 390, + "minitemp_set": 0, + "maxhum_set": 82, + "minihum_set": 20, + "temp_alarm": "cancel", + "hum_alarm": "loweralarm", + "temp_sensitivity": 6, + "hum_sensitivity": 6 + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "va_temperature", + "config_item": { + "statusFormat": { + "va_temperature": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "2": { + "value_convert": "default", + "status_code": "humidity_value", + "config_item": { + "statusFormat": { + "va_humidity": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "4": { + "value_convert": "default", + "status_code": "battery_percentage", + "config_item": { + "statusFormat": { + "battery_percentage": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "9": { + "value_convert": "default", + "status_code": "temp_unit_convert", + "config_item": { + "statusFormat": { + "temp_unit_convert": "$" + }, + "valueDesc": { + "range": ["c", "f"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "10": { + "value_convert": "default", + "status_code": "maxtemp_set", + "config_item": { + "statusFormat": { + "maxtemp_set": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "11": { + "value_convert": "default", + "status_code": "minitemp_set", + "config_item": { + "statusFormat": { + "minitemp_set": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": -200, + "max": 600, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "12": { + "value_convert": "default", + "status_code": "maxhum_set", + "config_item": { + "statusFormat": { + "maxhum_set": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "13": { + "value_convert": "default", + "status_code": "minihum_set", + "config_item": { + "statusFormat": { + "minihum_set": "$" + }, + "valueDesc": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "14": { + "value_convert": "default", + "status_code": "temp_alarm", + "config_item": { + "statusFormat": { + "temp_alarm": "$" + }, + "valueDesc": { + "range": ["loweralarm", "upperalarm", "cancel"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "15": { + "value_convert": "default", + "status_code": "hum_alarm", + "config_item": { + "statusFormat": { + "hum_alarm": "$" + }, + "valueDesc": { + "range": ["loweralarm", "upperalarm", "cancel"] + }, + "valueType": "Enum", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "19": { + "value_convert": "default", + "status_code": "temp_sensitivity", + "config_item": { + "statusFormat": { + "temp_sensitivity": "$" + }, + "valueDesc": { + "unit": "Ôäâ", + "min": 3, + "max": 20, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + }, + "20": { + "value_convert": "default", + "status_code": "hum_sensitivity", + "config_item": { + "statusFormat": { + "hum_sensitivity": "$" + }, + "valueDesc": { + "unit": "%", + "min": 3, + "max": 20, + "scale": 0, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "xflodz7oja0pndk3" + } + } + } +} diff --git a/tests/components/tuya/fixtures/wsdykq_ay30hrndaogxclh0.json b/tests/components/tuya/fixtures/wsdykq_ay30hrndaogxclh0.json new file mode 100644 index 00000000000..3d92f867fce --- /dev/null +++ b/tests/components/tuya/fixtures/wsdykq_ay30hrndaogxclh0.json @@ -0,0 +1,22 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "LCDÕ▒ŵ©®µ╣┐Õ║ªõ©çÞâ¢ÚüѵĺÕÖ¿", + "category": "wsdykq", + "product_id": "ay30hrndaogxclh0", + "product_name": "LCDÕ▒ŵ©®µ╣┐Õ║ªõ©çÞâ¢ÚüѵĺÕÖ¿", + "online": false, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-11-16T17:28:06+00:00", + "create_time": "2025-11-16T17:28:06+00:00", + "update_time": "2025-11-16T17:28:06+00:00", + "function": {}, + "status_range": {}, + "status": {}, + "set_up": false, + "support_local": true, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/zndb_gqmmtjclqb7reg5p.json b/tests/components/tuya/fixtures/zndb_gqmmtjclqb7reg5p.json new file mode 100644 index 00000000000..88c87f7d31c --- /dev/null +++ b/tests/components/tuya/fixtures/zndb_gqmmtjclqb7reg5p.json @@ -0,0 +1,22 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Wi-Fi Meter(Bi-Directional)", + "category": "zndb", + "product_id": "gqmmtjclqb7reg5p", + "product_name": "PC321-W-TY(Bi-Directional)", + "online": true, + "sub": false, + "time_zone": "-03:00", + "active_time": "2025-08-07T20:27:09+00:00", + "create_time": "2025-08-07T20:27:09+00:00", + "update_time": "2025-08-07T20:27:09+00:00", + "function": {}, + "status_range": {}, + "status": {}, + "set_up": false, + "support_local": true, + "local_strategy": {} +} diff --git a/tests/components/tuya/fixtures/zndb_z95s7p3z54xbsjnl.json b/tests/components/tuya/fixtures/zndb_z95s7p3z54xbsjnl.json new file mode 100644 index 00000000000..ccc333855ff --- /dev/null +++ b/tests/components/tuya/fixtures/zndb_z95s7p3z54xbsjnl.json @@ -0,0 +1,136 @@ +{ + "endpoint": "https://apigw.tuyaus.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "WIFI Dual Meter", + "category": "zndb", + "product_id": "z95s7p3z54xbsjnl", + "product_name": "WIFI Dual Meter", + "online": false, + "sub": false, + "time_zone": "-03:00", + "active_time": "2024-10-08T14:10:35+00:00", + "create_time": "2024-10-08T14:10:35+00:00", + "update_time": "2024-10-08T14:10:35+00:00", + "function": { + "forward_energy_total": { + "type": "Integer", + "value": { + "unit": "KWH", + "min": 0, + "max": 99999999, + "scale": 2, + "step": 1 + } + }, + "reverse_energy_total": { + "type": "Integer", + "value": { + "unit": "KWH", + "min": 0, + "max": 99999999, + "scale": 2, + "step": 1 + } + } + }, + "status_range": { + "forward_energy_total": { + "type": "Integer", + "value": { + "unit": "KWH", + "min": 0, + "max": 99999999, + "scale": 2, + "step": 1 + } + }, + "reverse_energy_total": { + "type": "Integer", + "value": { + "unit": "KWH", + "min": 0, + "max": 99999999, + "scale": 2, + "step": 1 + } + }, + "total_power": { + "type": "Integer", + "value": { + "unit": "W", + "min": -99999999, + "max": 99999999, + "scale": 1, + "step": 1 + } + } + }, + "status": { + "forward_energy_total": 259939, + "reverse_energy_total": 200008, + "total_power": -4095 + }, + "set_up": true, + "support_local": true, + "local_strategy": { + "1": { + "value_convert": "default", + "status_code": "forward_energy_total", + "config_item": { + "statusFormat": { + "forward_energy_total": "$" + }, + "valueDesc": { + "unit": "KWH", + "min": 0, + "max": 99999999, + "scale": 2, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "z95s7p3z54xbsjnl" + } + }, + "2": { + "value_convert": "default", + "status_code": "reverse_energy_total", + "config_item": { + "statusFormat": { + "reverse_energy_total": "$" + }, + "valueDesc": { + "unit": "KWH", + "min": 0, + "max": 99999999, + "scale": 2, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "z95s7p3z54xbsjnl" + } + }, + "115": { + "value_convert": "default", + "status_code": "total_power", + "config_item": { + "statusFormat": { + "total_power": "$" + }, + "valueDesc": { + "unit": "W", + "min": -99999999, + "max": 99999999, + "scale": 1, + "step": 1 + }, + "valueType": "Integer", + "enumMappingMap": {}, + "pid": "z95s7p3z54xbsjnl" + } + } + } +} diff --git a/tests/components/tuya/snapshots/test_alarm_control_panel.ambr b/tests/components/tuya/snapshots/test_alarm_control_panel.ambr index 337b579c7da..6711b0f496a 100644 --- a/tests/components/tuya/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/tuya/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_binary_sensor.ambr b/tests/components/tuya/snapshots/test_binary_sensor.ambr index 2d32b5bedff..82004e81c4f 100644 --- a/tests/components/tuya/snapshots/test_binary_sensor.ambr +++ b/tests/components/tuya/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safety', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feeding', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrost', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank full', 'options': dict({ }), 'original_device_class': , @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Defrost', 'options': dict({ }), 'original_device_class': , @@ -313,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank full', 'options': dict({ }), 'original_device_class': , @@ -362,6 +369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wet', 'options': dict({ }), 'original_device_class': , @@ -411,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -460,6 +469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -509,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -558,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -607,6 +619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas', 'options': dict({ }), 'original_device_class': , @@ -656,6 +669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -705,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -754,6 +769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -803,6 +819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , @@ -852,6 +869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bag full', 'options': dict({ }), 'original_device_class': , @@ -901,6 +919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cover off', 'options': dict({ }), 'original_device_class': , @@ -950,6 +969,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , @@ -999,6 +1019,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -1048,6 +1069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1076,6 +1098,56 @@ 'state': 'unavailable', }) # --- +# name: test_platform_setup_and_discovery[binary_sensor.pir_motion-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.pir_motion', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Motion', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Motion', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'tuya.kkgbskmfejn67l1orippir', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[binary_sensor.pir_motion-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'motion', + 'friendly_name': 'PIR Motion', + }), + 'context': , + 'entity_id': 'binary_sensor.pir_motion', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- # name: test_platform_setup_and_discovery[binary_sensor.pir_outside_stairs_motion-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1097,6 +1169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -1146,6 +1219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion', 'options': dict({ }), 'original_device_class': , @@ -1195,6 +1269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1244,6 +1319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1293,6 +1369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1342,6 +1419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging', 'options': dict({ }), 'original_device_class': , @@ -1391,6 +1469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , @@ -1440,6 +1519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': None, @@ -1488,6 +1568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Safety', 'options': dict({ }), 'original_device_class': , @@ -1537,6 +1618,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1586,6 +1668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1635,6 +1718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Occupancy', 'options': dict({ }), 'original_device_class': , @@ -1684,6 +1768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -1733,6 +1818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moisture', 'options': dict({ }), 'original_device_class': , @@ -1782,6 +1868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke', 'options': dict({ }), 'original_device_class': , @@ -1831,6 +1918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -1880,6 +1968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Problem', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tuya/snapshots/test_button.ambr b/tests/components/tuya/snapshots/test_button.ambr index 4fa87543ff6..d81d210c187 100644 --- a/tests/components/tuya/snapshots/test_button.ambr +++ b/tests/components/tuya/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Factory reset', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual clean', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Factory reset', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Manual clean', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset duster cloth', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset edge brush', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset filter', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset map', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset roll brush', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_camera.ambr b/tests/components/tuya/snapshots/test_camera.ambr index d39e33510f5..020333c4fc6 100644 --- a/tests/components/tuya/snapshots/test_camera.ambr +++ b/tests/components/tuya/snapshots/test_camera.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -128,6 +130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -235,6 +239,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -288,6 +293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -341,6 +347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_climate.ambr b/tests/components/tuya/snapshots/test_climate.ambr index 286f04b649f..209acb5d48b 100644 --- a/tests/components/tuya/snapshots/test_climate.ambr +++ b/tests/components/tuya/snapshots/test_climate.ambr @@ -32,6 +32,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -82,13 +83,13 @@ 'capabilities': dict({ 'hvac_modes': list([ , - , - , , ]), 'max_temp': 35.0, 'min_temp': 5.0, 'preset_modes': list([ + 'auto', + 'manual', 'off', ]), 'target_temp_step': 1.0, @@ -108,6 +109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -128,13 +130,13 @@ 'friendly_name': 'Anbau', 'hvac_modes': list([ , - , - , , ]), 'max_temp': 35.0, 'min_temp': 5.0, 'preset_modes': list([ + 'auto', + 'manual', 'off', ]), 'supported_features': , @@ -157,13 +159,13 @@ 'hvac_modes': list([ , , - , - , ]), 'max_temp': 70.0, 'min_temp': 1.0, 'preset_modes': list([ 'holiday', + 'auto', + 'manual', 'eco', ]), 'target_temp_step': 0.5, @@ -183,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -205,14 +208,14 @@ 'hvac_modes': list([ , , - , - , ]), 'max_temp': 70.0, 'min_temp': 1.0, 'preset_mode': None, 'preset_modes': list([ 'holiday', + 'auto', + 'manual', 'eco', ]), 'supported_features': , @@ -256,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -328,6 +332,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -402,6 +407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -447,13 +453,13 @@ 'capabilities': dict({ 'hvac_modes': list([ , - , - , , ]), 'max_temp': 35.0, 'min_temp': 5.0, 'preset_modes': list([ + 'auto', + 'manual', 'off', ]), 'target_temp_step': 1.0, @@ -473,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -494,14 +501,14 @@ 'friendly_name': 'Empore', 'hvac_modes': list([ , - , - , , ]), 'max_temp': 35.0, 'min_temp': 5.0, 'preset_mode': None, 'preset_modes': list([ + 'auto', + 'manual', 'off', ]), 'supported_features': , @@ -525,12 +532,12 @@ 'hvac_modes': list([ , , - , - , ]), 'max_temp': 35.0, 'min_temp': 5.0, 'preset_modes': list([ + 'auto', + 'manual', 'off', ]), 'target_temp_step': 1.0, @@ -550,6 +557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -572,13 +580,13 @@ 'hvac_modes': list([ , , - , - , ]), 'max_temp': 35.0, 'min_temp': 5.0, 'preset_mode': None, 'preset_modes': list([ + 'auto', + 'manual', 'off', ]), 'supported_features': , @@ -620,6 +628,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -681,6 +690,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -749,6 +759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -824,6 +835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -903,6 +915,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -976,6 +989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1042,6 +1056,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1092,12 +1107,12 @@ 'hvac_modes': list([ , , - , - , ]), 'max_temp': 5.9, 'min_temp': 0.1, 'preset_modes': list([ + 'auto', + 'manual', 'holiday', ]), 'target_temp_step': 0.5, @@ -1117,6 +1132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1139,13 +1155,13 @@ 'hvac_modes': list([ , , - , - , ]), 'max_temp': 5.9, 'min_temp': 0.1, 'preset_mode': None, 'preset_modes': list([ + 'auto', + 'manual', 'holiday', ]), 'supported_features': , @@ -1169,10 +1185,13 @@ 'hvac_modes': list([ , , - , ]), 'max_temp': 90.0, 'min_temp': 5.0, + 'preset_modes': list([ + 'auto', + 'manual', + ]), 'target_temp_step': 1.0, }), 'config_entry_id': , @@ -1190,6 +1209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1198,7 +1218,7 @@ 'platform': 'tuya', 'previous_unique_id': None, 'suggested_object_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': 'tuya.sb3zdertrw50bgogkw', 'unit_of_measurement': None, @@ -1212,11 +1232,15 @@ 'hvac_modes': list([ , , - , ]), 'max_temp': 90.0, 'min_temp': 5.0, - 'supported_features': , + 'preset_mode': None, + 'preset_modes': list([ + 'auto', + 'manual', + ]), + 'supported_features': , 'target_temp_step': 1.0, 'temperature': 12.0, }), @@ -1261,6 +1285,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1332,6 +1357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1398,6 +1424,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_cover.ambr b/tests/components/tuya/snapshots/test_cover.ambr index 916fcd2fee8..c424bfaf74d 100644 --- a/tests/components/tuya/snapshots/test_cover.ambr +++ b/tests/components/tuya/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -122,6 +124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -173,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -223,6 +227,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -274,6 +279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door 1', 'options': dict({ }), 'original_device_class': , @@ -324,6 +330,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -374,6 +381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Blind', 'options': dict({ }), 'original_device_class': , @@ -425,6 +433,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -476,6 +485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -527,6 +537,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -578,6 +589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -629,6 +641,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -680,6 +693,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -731,6 +745,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , @@ -782,6 +797,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Curtain', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tuya/snapshots/test_event.ambr b/tests/components/tuya/snapshots/test_event.ambr index 434aaebdc04..7edb4219860 100644 --- a/tests/components/tuya/snapshots/test_event.ambr +++ b/tests/components/tuya/snapshots/test_event.ambr @@ -47,6 +47,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 1', 'options': dict({ }), 'original_device_class': , @@ -106,6 +107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 2', 'options': dict({ }), 'original_device_class': , @@ -166,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Button 1', 'options': dict({ }), 'original_device_class': , @@ -225,6 +228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell message', 'options': dict({ }), 'original_device_class': , @@ -283,6 +287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell message', 'options': dict({ }), 'original_device_class': , @@ -341,6 +346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell picture', 'options': dict({ }), 'original_device_class': , @@ -399,6 +405,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell message', 'options': dict({ }), 'original_device_class': , @@ -457,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell message', 'options': dict({ }), 'original_device_class': , @@ -515,6 +523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell picture', 'options': dict({ }), 'original_device_class': , @@ -573,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell message', 'options': dict({ }), 'original_device_class': , @@ -631,6 +641,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Doorbell picture', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tuya/snapshots/test_fan.ambr b/tests/components/tuya/snapshots/test_fan.ambr index 423f93edc3f..70a250befa6 100644 --- a/tests/components/tuya/snapshots/test_fan.ambr +++ b/tests/components/tuya/snapshots/test_fan.ambr @@ -21,6 +21,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -74,6 +75,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -189,6 +192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -249,6 +253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -300,6 +305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -351,6 +357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -406,6 +413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -460,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -515,6 +524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -572,6 +582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -631,6 +642,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_humidifier.ambr b/tests/components/tuya/snapshots/test_humidifier.ambr index 13225239d02..e5e0edce0ea 100644 --- a/tests/components/tuya/snapshots/test_humidifier.ambr +++ b/tests/components/tuya/snapshots/test_humidifier.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -79,6 +80,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -191,6 +194,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -248,6 +252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -303,6 +308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tuya/snapshots/test_init.ambr b/tests/components/tuya/snapshots/test_init.ambr index 66c647b2b01..f048c1399a2 100644 --- a/tests/components/tuya/snapshots/test_init.ambr +++ b/tests/components/tuya/snapshots/test_init.ambr @@ -1,4 +1,35 @@ # serializer version: 1 +# name: test_device_registry[0hlcxgoadnrh03yaqkydsw] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + '0hlcxgoadnrh03yaqkydsw', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'LCDÕ▒ŵ©®µ╣┐Õ║ªõ©çÞâ¢ÚüѵĺÕÖ¿ (unsupported)', + 'model_id': 'ay30hrndaogxclh0', + 'name': 'LCDÕ▒ŵ©®µ╣┐Õ║ªõ©çÞâ¢ÚüѵĺÕÖ¿', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[0qtza8cv6q5rdxpxgcdsw] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -30,6 +61,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[0wep74vtderarfni] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + '0wep74vtderarfni', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'TV (unsupported)', + 'model_id': '47pew0', + 'name': 'TV', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[18yvbamhgkjc] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -278,6 +340,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[3kdnp0ajo7zdolfxgcdsw] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + '3kdnp0ajo7zdolfxgcdsw', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'T&H Sensor', + 'model_id': 'xflodz7oja0pndk3', + 'name': 'Sensor T & H Server Home', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[3phkffywh5nnlj5vbdnz] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -1921,6 +2014,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[a6ugbo3of3hqf4jojd] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'a6ugbo3of3hqf4jojd', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Lampada Wi-Fi+bluetooth', + 'model_id': 'oj4fqh3fo3obgu6a', + 'name': 'L├ímpara Ati', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[aa99hccfnzvypr3zjsywc] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -2913,6 +3037,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[cxbmhihohohk5bmeqdt] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'cxbmhihohohk5bmeqdt', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'WiFi Breaker', + 'model_id': 'emb5khohohihmbxc', + 'name': 'Server Fan', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[dBFBdywk9gTihUQmzc] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -3161,6 +3316,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[ej2zsznihehztkzqcaderarfni] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'ej2zsznihehztkzqcaderarfni', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Air Conditioning (unsupported)', + 'model_id': 'qzktzhehinzsz2je', + 'name': 'Air', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[eway2kw92ncuecarzc] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -3409,6 +3595,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[fov1huugujgfyl0xqkynw] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'fov1huugujgfyl0xqkynw', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Smart IR+RF Remote Control (unsupported)', + 'model_id': 'x0lyfgjuguuh1vof', + 'name': 'Smart IR+RF Remote Control', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[ftvxinxevpy21tbelc] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -4990,6 +5207,68 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[kkcwqzlvgcdsw] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'kkcwqzlvgcdsw', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Temperature Humidity Sensor', + 'model_id': 'vlzqwckk', + 'name': 'Temperature Humidity Sensor abelhas pasillo', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- +# name: test_device_registry[kkgbskmfejn67l1orip] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'kkgbskmfejn67l1orip', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'PIR', + 'model_id': 'o1l76njefmksbgkk', + 'name': 'PIR', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[klgxmpwvdhw7tzs8jd] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -5300,6 +5579,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[lnjsbx45z3p7s59zbdnz] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'lnjsbx45z3p7s59zbdnz', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'WIFI Dual Meter', + 'model_id': 'z95s7p3z54xbsjnl', + 'name': 'WIFI Dual Meter', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[mgcpxpmovasazerdps] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -5982,6 +6292,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[oxi73pj9a0ubr60pjd] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'oxi73pj9a0ubr60pjd', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'JRBULB', + 'model_id': 'p06rbu0a9jp37ixo', + 'name': 'Jardim Casa', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[p2gnclbiqxrbboagdd] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -6013,6 +6354,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[p5ger7bqlcjtmmqgbdnz] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'p5ger7bqlcjtmmqgbdnz', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'PC321-W-TY(Bi-Directional) (unsupported)', + 'model_id': 'gqmmtjclqb7reg5p', + 'name': 'Wi-Fi Meter(Bi-Directional)', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[p8xoxccrjbwy] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -6106,6 +6478,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[pdnimgsb3w0xko3kjd] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'pdnimgsb3w0xko3kjd', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Smart Bulb', + 'model_id': 'k3okx0w3bsgmindp', + 'name': 'Portal Casa Carro Jalimy', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[pfhwb1v3i7cifa2tcp] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -6850,6 +7253,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[rzt2knqamsxjp8f9ycjjh] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'rzt2knqamsxjp8f9ycjjh', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'MT15/MT29', + 'model_id': '9f8pjxsmaqnk2tzr', + 'name': 'MT15/MT29', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[s3zzjdcfrip] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -7315,6 +7749,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[syep74caderarfni] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'syep74caderarfni', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Air Conditioner (unsupported)', + 'model_id': '47peys', + 'name': 'Ar', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[t5zosev6h6wmwyrajbwy] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -8059,6 +8524,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[w9hdtm88xj5crtc1qdt] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'w9hdtm88xj5crtc1qdt', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'WiFi Breaker', + 'model_id': '1ctrc5jx88mtdh9w', + 'name': 'Puerta Casa ', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[wc6mumew8inrivi9zc] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -8245,6 +8741,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[xms6qowipdvjnkdgqdt] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'xms6qowipdvjnkdgqdt', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'Smart Switch Module', + 'model_id': 'gdknjvdpiwoq6smx', + 'name': 'Jardim frontal ', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[y1dkg3disbacmqfyjd] DeviceRegistryEntrySnapshot({ 'area_id': None, @@ -8834,6 +9361,37 @@ 'via_device_id': None, }) # --- +# name: test_device_registry[zwnoax1om13nulplvtderarfni] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': , + 'config_entries_subentries': , + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': None, + 'id': , + 'identifiers': set({ + tuple( + 'tuya', + 'zwnoax1om13nulplvtderarfni', + ), + }), + 'labels': set({ + }), + 'manufacturer': 'Tuya', + 'model': 'TV (unsupported)', + 'model_id': 'lplun31mo1xaonwz', + 'name': 'TV', + 'name_by_user': None, + 'primary_config_entry': , + 'serial_number': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- # name: test_device_registry[zyutbek7wdm1b4cgzckw] DeviceRegistryEntrySnapshot({ 'area_id': None, diff --git a/tests/components/tuya/snapshots/test_light.ambr b/tests/components/tuya/snapshots/test_light.ambr index 54b0c812ef3..bbb7d2e31dc 100644 --- a/tests/components/tuya/snapshots/test_light.ambr +++ b/tests/components/tuya/snapshots/test_light.ambr @@ -29,6 +29,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -112,6 +113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -174,6 +176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -251,6 +254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -312,6 +316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -370,6 +375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -431,6 +437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light', 'options': dict({ }), 'original_device_class': None, @@ -488,6 +495,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light', 'options': dict({ }), 'original_device_class': None, @@ -549,6 +557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -630,6 +639,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -712,6 +722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -785,6 +796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -857,6 +869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -928,6 +941,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1000,6 +1014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1078,6 +1093,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1138,6 +1154,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1220,6 +1237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1299,6 +1317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1366,6 +1385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1439,6 +1459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1508,6 +1529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1570,6 +1592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light 1', 'options': dict({ }), 'original_device_class': None, @@ -1632,6 +1655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1704,6 +1728,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1775,6 +1800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1827,6 +1853,73 @@ 'state': 'on', }) # --- +# name: test_platform_setup_and_discovery[light.jardim_casa-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max_color_temp_kelvin': 6500, + 'max_mireds': 500, + 'min_color_temp_kelvin': 2000, + 'min_mireds': 153, + 'supported_color_modes': list([ + , + , + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'light', + 'entity_category': None, + 'entity_id': 'light.jardim_casa', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'tuya.oxi73pj9a0ubr60pjdswitch_led', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[light.jardim_casa-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Jardim Casa', + 'max_color_temp_kelvin': 6500, + 'max_mireds': 500, + 'min_color_temp_kelvin': 2000, + 'min_mireds': 153, + 'supported_color_modes': list([ + , + , + ]), + 'supported_features': , + }), + 'context': , + 'entity_id': 'light.jardim_casa', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- # name: test_platform_setup_and_discovery[light.kattenbak_light-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1852,6 +1945,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light', 'options': dict({ }), 'original_device_class': None, @@ -1884,6 +1978,80 @@ 'state': 'off', }) # --- +# name: test_platform_setup_and_discovery[light.l_impara_ati-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max_color_temp_kelvin': 6500, + 'max_mireds': 500, + 'min_color_temp_kelvin': 2000, + 'min_mireds': 153, + 'supported_color_modes': list([ + , + , + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'light', + 'entity_category': None, + 'entity_id': 'light.l_impara_ati', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'tuya.a6ugbo3of3hqf4jojdswitch_led', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[light.l_impara_ati-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'brightness': None, + 'color_mode': None, + 'color_temp': None, + 'color_temp_kelvin': None, + 'friendly_name': 'L├ímpara Ati', + 'hs_color': None, + 'max_color_temp_kelvin': 6500, + 'max_mireds': 500, + 'min_color_temp_kelvin': 2000, + 'min_mireds': 153, + 'rgb_color': None, + 'supported_color_modes': list([ + , + , + ]), + 'supported_features': , + 'xy_color': None, + }), + 'context': , + 'entity_id': 'light.l_impara_ati', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[light.landing-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -1914,6 +2082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1987,6 +2156,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2070,6 +2240,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2136,6 +2307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2202,6 +2374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2274,6 +2447,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2346,6 +2520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2424,6 +2599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backlight', 'options': dict({ }), 'original_device_class': None, @@ -2486,6 +2662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2547,6 +2724,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backlight', 'options': dict({ }), 'original_device_class': None, @@ -2609,6 +2787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2691,6 +2870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2755,6 +2935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2816,6 +2997,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2853,6 +3035,73 @@ 'state': 'off', }) # --- +# name: test_platform_setup_and_discovery[light.portal_casa_carro_jalimy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max_color_temp_kelvin': 6500, + 'max_mireds': 500, + 'min_color_temp_kelvin': 2000, + 'min_mireds': 153, + 'supported_color_modes': list([ + , + , + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'light', + 'entity_category': None, + 'entity_id': 'light.portal_casa_carro_jalimy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'tuya.pdnimgsb3w0xko3kjdswitch_led', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[light.portal_casa_carro_jalimy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Portal Casa Carro Jalimy', + 'max_color_temp_kelvin': 6500, + 'max_mireds': 500, + 'min_color_temp_kelvin': 2000, + 'min_mireds': 153, + 'supported_color_modes': list([ + , + , + ]), + 'supported_features': , + }), + 'context': , + 'entity_id': 'light.portal_casa_carro_jalimy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- # name: test_platform_setup_and_discovery[light.powerasia_r2-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -2882,6 +3131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2949,6 +3199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backlight', 'options': dict({ }), 'original_device_class': None, @@ -3010,6 +3261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3081,6 +3333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3145,6 +3398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3217,6 +3471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3285,6 +3540,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3356,6 +3612,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3413,6 +3670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3479,6 +3737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3544,6 +3803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3610,6 +3870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3678,6 +3939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backlight', 'options': dict({ }), 'original_device_class': None, @@ -3739,6 +4001,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3806,6 +4069,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Backlight', 'options': dict({ }), 'original_device_class': None, @@ -3867,6 +4131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -3927,6 +4192,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_number.ambr b/tests/components/tuya/snapshots/test_number.ambr index 40413002bf4..743b78164a4 100644 --- a/tests/components/tuya/snapshots/test_number.ambr +++ b/tests/components/tuya/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm duration', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature correction', 'options': dict({ }), 'original_device_class': None, @@ -200,6 +203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feed', 'options': dict({ }), 'original_device_class': None, @@ -316,6 +321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voice times', 'options': dict({ }), 'original_device_class': None, @@ -374,6 +380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery backup reserve', 'options': dict({ }), 'original_device_class': None, @@ -432,6 +439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter output power limit', 'options': dict({ }), 'original_device_class': , @@ -491,6 +499,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feed', 'options': dict({ }), 'original_device_class': None, @@ -549,6 +558,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking temperature', 'options': dict({ }), 'original_device_class': None, @@ -607,6 +617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking temperature 2', 'options': dict({ }), 'original_device_class': None, @@ -665,6 +676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': , @@ -724,6 +736,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm maximum', 'options': dict({ }), 'original_device_class': None, @@ -782,6 +795,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm minimum', 'options': dict({ }), 'original_device_class': None, @@ -840,6 +854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Installation height', 'options': dict({ }), 'original_device_class': , @@ -899,6 +914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum liquid depth', 'options': dict({ }), 'original_device_class': , @@ -958,6 +974,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Far detection', 'options': dict({ }), 'original_device_class': , @@ -1017,6 +1034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Near detection', 'options': dict({ }), 'original_device_class': , @@ -1076,6 +1094,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1134,6 +1153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 1', 'options': dict({ }), 'original_device_class': , @@ -1193,6 +1213,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 2', 'options': dict({ }), 'original_device_class': , @@ -1252,6 +1273,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 3', 'options': dict({ }), 'original_device_class': , @@ -1311,6 +1333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 4', 'options': dict({ }), 'original_device_class': , @@ -1370,6 +1393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 5', 'options': dict({ }), 'original_device_class': , @@ -1429,6 +1453,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 6', 'options': dict({ }), 'original_device_class': , @@ -1488,6 +1513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 7', 'options': dict({ }), 'original_device_class': , @@ -1547,6 +1573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Irrigation duration 8', 'options': dict({ }), 'original_device_class': , @@ -1606,6 +1633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature correction', 'options': dict({ }), 'original_device_class': None, @@ -1664,6 +1692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delay clean time', 'options': dict({ }), 'original_device_class': , @@ -1723,6 +1752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -1781,6 +1811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm delay', 'options': dict({ }), 'original_device_class': , @@ -1840,6 +1871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Arm delay', 'options': dict({ }), 'original_device_class': , @@ -1899,6 +1931,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren duration', 'options': dict({ }), 'original_device_class': , @@ -1958,6 +1991,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Delay clean time', 'options': dict({ }), 'original_device_class': , @@ -2017,6 +2051,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm maximum', 'options': dict({ }), 'original_device_class': None, @@ -2075,6 +2110,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm minimum', 'options': dict({ }), 'original_device_class': None, @@ -2133,6 +2169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Installation height', 'options': dict({ }), 'original_device_class': , @@ -2192,6 +2229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum liquid depth', 'options': dict({ }), 'original_device_class': , @@ -2251,6 +2289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time', 'options': dict({ }), 'original_device_class': None, @@ -2309,6 +2348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time', 'options': dict({ }), 'original_device_class': None, @@ -2367,6 +2407,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature correction', 'options': dict({ }), 'original_device_class': None, @@ -2425,6 +2466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -2483,6 +2525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking temperature', 'options': dict({ }), 'original_device_class': None, @@ -2541,6 +2584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking time', 'options': dict({ }), 'original_device_class': None, @@ -2599,6 +2643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -2657,6 +2702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -2715,6 +2761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature correction', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_select.ambr b/tests/components/tuya/snapshots/test_select.ambr index a880f04c4d6..74a6029ea66 100644 --- a/tests/components/tuya/snapshots/test_select.ambr +++ b/tests/components/tuya/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -203,6 +206,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -263,6 +267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -323,6 +328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -381,6 +387,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target humidity', 'options': dict({ }), 'original_device_class': None, @@ -439,6 +446,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -498,6 +506,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -557,6 +566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -616,6 +626,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -676,6 +687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather delay', 'options': dict({ }), 'original_device_class': None, @@ -736,6 +748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -795,6 +808,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -853,6 +867,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -914,6 +929,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -976,6 +992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Anti-flicker', 'options': dict({ }), 'original_device_class': None, @@ -1035,6 +1052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1094,6 +1112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night vision', 'options': dict({ }), 'original_device_class': None, @@ -1152,6 +1171,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Record mode', 'options': dict({ }), 'original_device_class': None, @@ -1209,6 +1229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1266,6 +1287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IPC mode', 'options': dict({ }), 'original_device_class': None, @@ -1324,6 +1346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1382,6 +1405,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Record mode', 'options': dict({ }), 'original_device_class': None, @@ -1440,6 +1464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1499,6 +1524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Night vision', 'options': dict({ }), 'original_device_class': None, @@ -1557,6 +1583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Record mode', 'options': dict({ }), 'original_device_class': None, @@ -1614,6 +1641,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1672,6 +1700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1730,6 +1759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Record mode', 'options': dict({ }), 'original_device_class': None, @@ -1787,6 +1817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -1844,6 +1875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter work mode', 'options': dict({ }), 'original_device_class': None, @@ -1904,6 +1936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -1966,6 +1999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -2027,6 +2061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -2087,6 +2122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -2146,6 +2182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -2206,6 +2243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -2265,6 +2303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor mode', 'options': dict({ }), 'original_device_class': None, @@ -2323,6 +2362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -2382,6 +2422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -2441,6 +2482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -2500,6 +2542,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -2559,6 +2602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -2618,6 +2662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -2677,6 +2722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -2736,6 +2782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -2794,6 +2841,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Record mode', 'options': dict({ }), 'original_device_class': None, @@ -2853,6 +2901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather delay', 'options': dict({ }), 'original_device_class': None, @@ -2913,6 +2962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -2972,6 +3022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -3032,6 +3083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -3092,6 +3144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -3151,6 +3204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion detection sensitivity', 'options': dict({ }), 'original_device_class': None, @@ -3213,6 +3267,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -3278,6 +3333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -3313,6 +3369,66 @@ 'state': 'unknown', }) # --- +# name: test_platform_setup_and_discovery[select.jardim_frontal_power_on_behavior-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + '0', + '1', + '2', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': , + 'entity_id': 'select.jardim_frontal_power_on_behavior', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power on behavior', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Power on behavior', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'relay_status', + 'unique_id': 'tuya.xms6qowipdvjnkdgqdtrelay_status', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[select.jardim_frontal_power_on_behavior-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Jardim frontal Power on behavior', + 'options': list([ + '0', + '1', + '2', + ]), + }), + 'context': , + 'entity_id': 'select.jardim_frontal_power_on_behavior', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- # name: test_platform_setup_and_discovery[select.jardin_fraises_power_on_behavior-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -3340,6 +3456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -3399,6 +3516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -3458,6 +3576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -3520,6 +3639,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -3581,6 +3701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor mode', 'options': dict({ }), 'original_device_class': None, @@ -3645,6 +3766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Spraying level', 'options': dict({ }), 'original_device_class': None, @@ -3710,6 +3832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -3769,6 +3892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -3829,6 +3953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Countdown', 'options': dict({ }), 'original_device_class': None, @@ -3890,6 +4015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level', 'options': dict({ }), 'original_device_class': None, @@ -3950,6 +4076,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Up/Down', 'options': dict({ }), 'original_device_class': None, @@ -4009,6 +4136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Anti-flicker', 'options': dict({ }), 'original_device_class': None, @@ -4067,6 +4195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IPC mode', 'options': dict({ }), 'original_device_class': None, @@ -4125,6 +4254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -4184,6 +4314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -4242,6 +4373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor mode', 'options': dict({ }), 'original_device_class': None, @@ -4299,6 +4431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor mode', 'options': dict({ }), 'original_device_class': None, @@ -4330,6 +4463,66 @@ 'state': 'forward', }) # --- +# name: test_platform_setup_and_discovery[select.puerta_casa_power_on_behavior-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + '0', + '1', + '2', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': , + 'entity_id': 'select.puerta_casa_power_on_behavior', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power on behavior', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Power on behavior', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'relay_status', + 'unique_id': 'tuya.w9hdtm88xj5crtc1qdtrelay_status', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[select.puerta_casa_power_on_behavior-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Puerta Casa Power on behavior', + 'options': list([ + '0', + '1', + '2', + ]), + }), + 'context': , + 'entity_id': 'select.puerta_casa_power_on_behavior', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- # name: test_platform_setup_and_discovery[select.raspy4_home_assistant_indicator_light_mode-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -4357,6 +4550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -4416,6 +4610,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -4475,6 +4670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -4534,6 +4730,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -4593,6 +4790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -4625,6 +4823,66 @@ 'state': 'power_on', }) # --- +# name: test_platform_setup_and_discovery[select.server_fan_power_on_behavior-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + '0', + '1', + '2', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': , + 'entity_id': 'select.server_fan_power_on_behavior', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Power on behavior', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Power on behavior', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'relay_status', + 'unique_id': 'tuya.cxbmhihohohk5bmeqdtrelay_status', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[select.server_fan_power_on_behavior-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Server Fan Power on behavior', + 'options': list([ + '0', + '1', + '2', + ]), + }), + 'context': , + 'entity_id': 'select.server_fan_power_on_behavior', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2', + }) +# --- # name: test_platform_setup_and_discovery[select.siren_siren_mode-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -4653,6 +4911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren mode', 'options': dict({ }), 'original_device_class': None, @@ -4714,6 +4973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -4775,6 +5035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -4834,6 +5095,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odor elimination mode', 'options': dict({ }), 'original_device_class': None, @@ -4893,6 +5155,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather delay', 'options': dict({ }), 'original_device_class': None, @@ -4953,6 +5216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -5012,6 +5276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -5071,6 +5336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -5130,6 +5396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -5189,6 +5456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -5255,6 +5523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level', 'options': dict({ }), 'original_device_class': None, @@ -5329,6 +5598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level 1', 'options': dict({ }), 'original_device_class': None, @@ -5403,6 +5673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Level 2', 'options': dict({ }), 'original_device_class': None, @@ -5471,6 +5742,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, @@ -5531,6 +5803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water tank adjustment', 'options': dict({ }), 'original_device_class': None, @@ -5591,6 +5864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weather delay', 'options': dict({ }), 'original_device_class': None, @@ -5650,6 +5924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motor mode', 'options': dict({ }), 'original_device_class': None, @@ -5708,6 +5983,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -5767,6 +6043,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -5826,6 +6103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indicator light mode', 'options': dict({ }), 'original_device_class': None, @@ -5885,6 +6163,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, @@ -5944,6 +6223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power on behavior', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_sensor.ambr b/tests/components/tuya/snapshots/test_sensor.ambr index 1dccb909764..7366b0c16ce 100644 --- a/tests/components/tuya/snapshots/test_sensor.ambr +++ b/tests/components/tuya/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -137,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -188,6 +191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -247,6 +251,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -306,6 +311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -362,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -418,6 +425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -477,6 +485,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -536,6 +545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -592,6 +602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -651,6 +662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -710,6 +722,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -766,6 +779,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -818,6 +832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -877,6 +892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -928,6 +944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -978,6 +995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'ppm', @@ -1034,6 +1052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Formaldehyde', 'options': dict({ }), 'original_device_class': None, @@ -1086,6 +1105,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1139,6 +1159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -1192,6 +1213,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'μg/m³', @@ -1248,6 +1270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1304,6 +1327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volatile organic compounds', 'options': dict({ }), 'original_device_class': , @@ -1357,6 +1381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1410,6 +1435,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1466,6 +1492,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1525,6 +1552,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1581,6 +1609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -1632,6 +1661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1691,6 +1721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1750,6 +1781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1806,6 +1838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -1857,6 +1890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1916,6 +1950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1969,6 +2004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2022,6 +2058,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2075,6 +2112,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2131,6 +2169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2184,6 +2223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2243,6 +2283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2299,6 +2340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2355,6 +2397,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2411,6 +2454,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2470,6 +2514,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2523,6 +2568,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2576,6 +2622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -2629,6 +2676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2683,6 +2731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -2733,6 +2782,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2789,6 +2839,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2845,6 +2896,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heat index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2901,6 +2953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -2954,6 +3007,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -3007,6 +3061,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity', 'options': dict({ }), 'original_device_class': , @@ -3060,6 +3115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity channel 1', 'options': dict({ }), 'original_device_class': , @@ -3113,6 +3169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity channel 2', 'options': dict({ }), 'original_device_class': , @@ -3166,6 +3223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity channel 3', 'options': dict({ }), 'original_device_class': , @@ -3219,6 +3277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3275,6 +3334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3331,6 +3391,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature channel 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3387,6 +3448,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature channel 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3443,6 +3505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature channel 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3499,6 +3562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3555,6 +3619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3611,6 +3676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -3663,6 +3729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind chill index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3719,6 +3786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': None, @@ -3770,6 +3838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3829,6 +3898,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -3882,6 +3952,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last amount', 'options': dict({ }), 'original_device_class': None, @@ -3934,6 +4005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3990,6 +4062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery SOC', 'options': dict({ }), 'original_device_class': , @@ -4043,6 +4116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Inverter output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4099,6 +4173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery charge energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4155,6 +4230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime battery discharge energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4211,6 +4287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime inverter output energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4267,6 +4344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime off-grid port energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4323,6 +4401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lifetime PV energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4379,6 +4458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV channel 1 power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4435,6 +4515,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PV channel 2 power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4491,6 +4572,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total PV power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4547,6 +4629,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last amount', 'options': dict({ }), 'original_device_class': None, @@ -4599,6 +4682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4658,6 +4742,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4714,6 +4799,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4770,6 +4856,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4829,6 +4916,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -4882,6 +4970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4941,6 +5030,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -4994,6 +5084,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5050,6 +5141,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -5101,6 +5193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5160,6 +5253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -5213,6 +5307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5267,6 +5362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last operation duration', 'options': dict({ }), 'original_device_class': None, @@ -5318,6 +5414,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5371,6 +5468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5430,6 +5528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5486,6 +5585,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -5538,6 +5638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5597,6 +5698,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5656,6 +5758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5715,6 +5818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5771,6 +5875,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5827,6 +5932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5883,6 +5989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5942,6 +6049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5998,6 +6106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -6050,6 +6159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6109,6 +6219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6168,6 +6279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6227,6 +6339,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6283,6 +6396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6342,6 +6456,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6401,6 +6516,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6457,6 +6573,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6516,6 +6633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6575,6 +6693,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6631,6 +6750,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6687,6 +6807,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6746,6 +6867,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6802,6 +6924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -6853,6 +6976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6912,6 +7036,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6971,6 +7096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7027,6 +7153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -7078,6 +7205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7137,6 +7265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -7190,6 +7319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7249,6 +7379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7305,6 +7436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -7356,6 +7488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7413,6 +7546,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -7463,6 +7597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -7516,6 +7651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7572,6 +7708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -7628,6 +7765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -7681,6 +7819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7740,6 +7879,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7796,6 +7936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7852,6 +7993,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -7911,6 +8053,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -7970,6 +8113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8026,6 +8170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8085,6 +8230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -8138,6 +8284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total watering time', 'options': dict({ }), 'original_device_class': None, @@ -8190,6 +8337,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gas', 'options': dict({ }), 'original_device_class': None, @@ -8240,6 +8388,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -8290,6 +8439,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -8343,6 +8493,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8399,6 +8550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -8452,6 +8604,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8508,6 +8661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8564,6 +8718,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8623,6 +8778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8679,6 +8835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -8730,6 +8887,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -8789,6 +8947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': None, @@ -8841,6 +9000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -8897,6 +9057,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Depth', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -8953,6 +9114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Liquid level', 'options': dict({ }), 'original_device_class': None, @@ -9003,6 +9165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Liquid state', 'options': dict({ }), 'original_device_class': None, @@ -9053,6 +9216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -9104,6 +9268,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -9154,6 +9319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -9207,6 +9373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9263,6 +9430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': None, @@ -9315,6 +9483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -9368,6 +9537,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9424,6 +9594,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -9477,6 +9648,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -9530,6 +9702,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9586,6 +9759,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9645,6 +9819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9701,6 +9876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -9757,6 +9933,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -9814,6 +9991,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -9864,6 +10042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -9917,6 +10096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -9973,6 +10153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10032,6 +10213,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10088,6 +10270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -10139,6 +10322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10198,6 +10382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -10251,6 +10436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': None, @@ -10303,6 +10489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10362,6 +10549,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10418,6 +10606,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10474,6 +10663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10530,6 +10720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10589,6 +10780,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -10640,6 +10832,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -10688,6 +10881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -10736,6 +10930,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter utilization', 'options': dict({ }), 'original_device_class': None, @@ -10787,6 +10982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'μg/m³', @@ -10843,6 +11039,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cat weight', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -10899,6 +11096,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Excretion duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -10953,6 +11151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Excretion times (day)', 'options': dict({ }), 'original_device_class': None, @@ -11002,6 +11201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -11052,6 +11252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11111,6 +11312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11167,6 +11369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -11219,6 +11422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11276,6 +11480,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -11326,6 +11531,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': None, @@ -11378,6 +11584,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11437,6 +11644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11493,6 +11701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11549,6 +11758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11608,6 +11818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11667,6 +11878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11723,6 +11935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -11775,6 +11988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -11834,6 +12048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -11887,6 +12102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -11946,6 +12162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12002,6 +12219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12059,6 +12277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last operation duration', 'options': dict({ }), 'original_device_class': None, @@ -12110,6 +12329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -12163,6 +12383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -12216,6 +12437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12275,6 +12497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12334,6 +12557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12390,6 +12614,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12449,6 +12674,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12508,6 +12734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12564,6 +12791,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12623,6 +12851,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12682,6 +12911,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12738,6 +12968,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -12794,6 +13025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12850,6 +13082,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12906,6 +13139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -12965,6 +13199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13024,6 +13259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13080,6 +13316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13136,6 +13373,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13192,6 +13430,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13251,6 +13490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13310,6 +13550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13366,6 +13607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13425,6 +13667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13484,6 +13727,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13540,6 +13784,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13599,6 +13844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13658,6 +13904,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13714,6 +13961,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -13770,6 +14018,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13826,6 +14075,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': None, @@ -13878,6 +14128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -13908,6 +14159,432 @@ 'state': 'unavailable', }) # --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_air_quality_index-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_air_quality_index', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Air quality index', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Air quality index', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'air_quality_index', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhair_quality_index', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_air_quality_index-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'MT15/MT29 Air quality index', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_air_quality_index', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'level_1', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.mt15_mt29_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhbattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'MT15/MT29 Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_carbon_dioxide-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_carbon_dioxide', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Carbon dioxide', + 'options': dict({ + 'sensor.private': dict({ + 'suggested_unit_of_measurement': 'ppm', + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Carbon dioxide', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'carbon_dioxide', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhco2_value', + 'unit_of_measurement': 'ppm', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_carbon_dioxide-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'carbon_dioxide', + 'friendly_name': 'MT15/MT29 Carbon dioxide', + 'state_class': , + 'unit_of_measurement': 'ppm', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_carbon_dioxide', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '439.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_formaldehyde-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_formaldehyde', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Formaldehyde', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Formaldehyde', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'formaldehyde', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhch2o_value', + 'unit_of_measurement': 'mg/m┬│', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_formaldehyde-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'MT15/MT29 Formaldehyde', + 'state_class': , + 'unit_of_measurement': 'mg/m┬│', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_formaldehyde', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.001', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_humidity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Humidity', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Humidity', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'humidity', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhhumidity_value', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_humidity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'humidity', + 'friendly_name': 'MT15/MT29 Humidity', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '68.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_pm10-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_pm10', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'PM10', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'PM10', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'pm10', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhpm10', + 'unit_of_measurement': 'ug/m┬│', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_pm10-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'MT15/MT29 PM10', + 'state_class': , + 'unit_of_measurement': 'ug/m┬│', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_pm10', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_pm2_5-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_pm2_5', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'PM2.5', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'PM2.5', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'pm25', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhpm25_value', + 'unit_of_measurement': 'ug/m┬│', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_pm2_5-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'MT15/MT29 PM2.5', + 'state_class': , + 'unit_of_measurement': 'ug/m┬│', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_pm2_5', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '11.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mt15_mt29_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'temperature', + 'unique_id': 'tuya.rzt2knqamsxjp8f9ycjjhtemp_current', + 'unit_of_measurement': 'Ôäâ', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.mt15_mt29_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'MT15/MT29 Temperature', + 'state_class': , + 'unit_of_measurement': 'Ôäâ', + }), + 'context': , + 'entity_id': 'sensor.mt15_mt29_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '27.0', + }) +# --- # name: test_platform_setup_and_discovery[sensor.n4_auto_current-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -13931,6 +14608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -13990,6 +14668,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14046,6 +14725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -14098,6 +14778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14157,6 +14838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -14210,6 +14892,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -14263,6 +14946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -14319,6 +15003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14378,6 +15063,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14434,6 +15120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -14485,6 +15172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14544,6 +15232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14603,6 +15292,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14662,6 +15352,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14718,6 +15409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14777,6 +15469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14836,6 +15529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase B voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -14892,6 +15586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -14951,6 +15646,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15010,6 +15706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase C voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -15066,6 +15763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15122,6 +15820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -15173,6 +15872,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -15223,6 +15923,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -15276,6 +15977,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -15332,6 +16034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -15385,6 +16088,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -15418,6 +16122,60 @@ 'state': '17.0', }) # --- +# name: test_platform_setup_and_discovery[sensor.pir_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.pir_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.kkgbskmfejn67l1oripbattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.pir_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'PIR Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.pir_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- # name: test_platform_setup_and_discovery[sensor.pir_outside_stairs_battery_state-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -15439,6 +16197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -15489,6 +16248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15545,6 +16305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV runtime', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15599,6 +16360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water level', 'options': dict({ }), 'original_device_class': None, @@ -15649,6 +16411,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pump duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15705,6 +16468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water usage duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15761,6 +16525,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cat weight', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15817,6 +16582,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Excretion duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -15871,6 +16637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Excretion times (day)', 'options': dict({ }), 'original_device_class': None, @@ -15920,6 +16687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -15970,6 +16738,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16026,6 +16795,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16082,6 +16852,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16136,6 +16907,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last operation duration', 'options': dict({ }), 'original_device_class': None, @@ -16187,6 +16959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon dioxide', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'ppm', @@ -16243,6 +17016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -16296,6 +17070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -16352,6 +17127,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Depth', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16408,6 +17184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Liquid level', 'options': dict({ }), 'original_device_class': None, @@ -16458,6 +17235,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Liquid state', 'options': dict({ }), 'original_device_class': None, @@ -16508,6 +17286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16567,6 +17346,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16623,6 +17403,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16679,6 +17460,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -16736,6 +17518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -16784,6 +17567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -16832,6 +17616,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -16882,6 +17667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -16935,6 +17721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -16994,6 +17781,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17050,6 +17838,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17086,6 +17875,167 @@ 'state': '2357.0', }) # --- +# name: test_platform_setup_and_discovery[sensor.sensor_t_h_server_home_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.sensor_t_h_server_home_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.3kdnp0ajo7zdolfxgcdswbattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.sensor_t_h_server_home_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Sensor T & H Server Home Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.sensor_t_h_server_home_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.sensor_t_h_server_home_humidity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.sensor_t_h_server_home_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Humidity', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Humidity', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'humidity', + 'unique_id': 'tuya.3kdnp0ajo7zdolfxgcdswva_humidity', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.sensor_t_h_server_home_humidity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'humidity', + 'friendly_name': 'Sensor T & H Server Home Humidity', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.sensor_t_h_server_home_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.sensor_t_h_server_home_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.sensor_t_h_server_home_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'temperature', + 'unique_id': 'tuya.3kdnp0ajo7zdolfxgcdswva_temperature', + 'unit_of_measurement': 'Ôäâ', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.sensor_t_h_server_home_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Sensor T & H Server Home Temperature', + 'state_class': , + 'unit_of_measurement': 'Ôäâ', + }), + 'context': , + 'entity_id': 'sensor.sensor_t_h_server_home_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '32.7', + }) +# --- # name: test_platform_setup_and_discovery[sensor.siren_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -17109,6 +18059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17162,6 +18113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cat weight', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -17218,6 +18170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Excretion duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17272,6 +18225,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Excretion times (day)', 'options': dict({ }), 'original_device_class': None, @@ -17323,6 +18277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17374,6 +18329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -17424,6 +18380,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17477,6 +18434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total watering time', 'options': dict({ }), 'original_device_class': None, @@ -17529,6 +18487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17582,6 +18541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ 'sensor.private': dict({ 'suggested_unit_of_measurement': 'ppm', @@ -17638,6 +18598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17689,6 +18650,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -17739,6 +18701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Smoke amount', 'options': dict({ }), 'original_device_class': None, @@ -17790,6 +18753,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -17841,6 +18805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -17891,6 +18856,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -17950,6 +18916,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18006,6 +18973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18062,6 +19030,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18121,6 +19090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18180,6 +19150,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18236,6 +19207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -18287,6 +19259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18346,6 +19319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -18397,6 +19371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -18447,6 +19422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18506,6 +19482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -18562,6 +19539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18618,6 +19596,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -18672,6 +19651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining time', 'options': dict({ }), 'original_device_class': None, @@ -18721,6 +19701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -18771,6 +19752,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18830,6 +19812,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18886,6 +19869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -18942,6 +19926,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -18999,6 +19984,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -19049,6 +20035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air pressure', 'options': dict({ }), 'original_device_class': None, @@ -19101,6 +20088,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19157,6 +20145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19213,6 +20202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heat index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19269,6 +20259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -19322,6 +20313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Illuminance', 'options': dict({ }), 'original_device_class': , @@ -19375,6 +20367,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity', 'options': dict({ }), 'original_device_class': , @@ -19428,6 +20421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity channel 1', 'options': dict({ }), 'original_device_class': , @@ -19481,6 +20475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity channel 2', 'options': dict({ }), 'original_device_class': , @@ -19534,6 +20529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outdoor humidity channel 3', 'options': dict({ }), 'original_device_class': , @@ -19587,6 +20583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation intensity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -19643,6 +20640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19699,6 +20697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature channel 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19755,6 +20754,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature channel 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19811,6 +20811,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Probe temperature channel 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19867,6 +20868,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -19923,6 +20925,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -19979,6 +20982,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV index', 'options': dict({ }), 'original_device_class': None, @@ -20031,6 +21035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind chill index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -20087,6 +21092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -20143,6 +21149,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -20196,6 +21203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -20249,6 +21257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -20282,6 +21291,167 @@ 'state': '20.0', }) # --- +# name: test_platform_setup_and_discovery[sensor.temperature_humidity_sensor_abelhas_pasillo_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.temperature_humidity_sensor_abelhas_pasillo_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.kkcwqzlvgcdswbattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.temperature_humidity_sensor_abelhas_pasillo_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Temperature Humidity Sensor abelhas pasillo Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.temperature_humidity_sensor_abelhas_pasillo_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.temperature_humidity_sensor_abelhas_pasillo_humidity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.temperature_humidity_sensor_abelhas_pasillo_humidity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Humidity', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Humidity', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'humidity', + 'unique_id': 'tuya.kkcwqzlvgcdswva_humidity', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.temperature_humidity_sensor_abelhas_pasillo_humidity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'humidity', + 'friendly_name': 'Temperature Humidity Sensor abelhas pasillo Humidity', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.temperature_humidity_sensor_abelhas_pasillo_humidity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.temperature_humidity_sensor_abelhas_pasillo_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.temperature_humidity_sensor_abelhas_pasillo_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Temperature', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Temperature', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'temperature', + 'unique_id': 'tuya.kkcwqzlvgcdswva_temperature', + 'unit_of_measurement': 'Ôäâ', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.temperature_humidity_sensor_abelhas_pasillo_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Temperature Humidity Sensor abelhas pasillo Temperature', + 'state_class': , + 'unit_of_measurement': 'Ôäâ', + }), + 'context': , + 'entity_id': 'sensor.temperature_humidity_sensor_abelhas_pasillo_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- # name: test_platform_setup_and_discovery[sensor.tournesol_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -20305,6 +21475,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -20358,6 +21529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -20411,6 +21583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning area', 'options': dict({ }), 'original_device_class': None, @@ -20463,6 +21636,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cleaning time', 'options': dict({ }), 'original_device_class': None, @@ -20515,6 +21689,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Duster cloth lifetime', 'options': dict({ }), 'original_device_class': None, @@ -20567,6 +21742,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -20619,6 +21795,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rolling brush lifetime', 'options': dict({ }), 'original_device_class': None, @@ -20671,6 +21848,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side brush lifetime', 'options': dict({ }), 'original_device_class': None, @@ -20723,6 +21901,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning area', 'options': dict({ }), 'original_device_class': None, @@ -20775,6 +21954,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning time', 'options': dict({ }), 'original_device_class': None, @@ -20827,6 +22007,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total cleaning times', 'options': dict({ }), 'original_device_class': None, @@ -20878,6 +22059,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -20931,6 +22113,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total watering time', 'options': dict({ }), 'original_device_class': None, @@ -20983,6 +22166,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21042,6 +22226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21098,6 +22283,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21154,6 +22340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21213,6 +22400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -21266,6 +22454,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -21320,6 +22509,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last operation duration', 'options': dict({ }), 'original_device_class': None, @@ -21371,6 +22561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21430,6 +22621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21486,6 +22678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21545,6 +22738,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter duration', 'options': dict({ }), 'original_device_class': None, @@ -21597,6 +22791,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pump duration', 'options': dict({ }), 'original_device_class': None, @@ -21649,6 +22844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -21702,6 +22898,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -21758,6 +22955,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -21817,6 +23015,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21873,6 +23072,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -21925,6 +23125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -21984,6 +23185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -22043,6 +23245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -22099,6 +23302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -22155,6 +23359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -22214,6 +23419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -22273,6 +23479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22329,6 +23536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -22362,6 +23570,177 @@ 'state': '0.19', }) # --- +# name: test_platform_setup_and_discovery[sensor.wifi_dual_meter_total_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.wifi_dual_meter_total_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Total energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total energy', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'total_energy', + 'unique_id': 'tuya.lnjsbx45z3p7s59zbdnzforward_energy_total', + 'unit_of_measurement': , + }) +# --- +# name: test_platform_setup_and_discovery[sensor.wifi_dual_meter_total_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'WIFI Dual Meter Total energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.wifi_dual_meter_total_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.wifi_dual_meter_total_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.wifi_dual_meter_total_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Total power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total power', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'total_power', + 'unique_id': 'tuya.lnjsbx45z3p7s59zbdnztotal_powerpower', + 'unit_of_measurement': 'W', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.wifi_dual_meter_total_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'WIFI Dual Meter Total power', + 'state_class': , + 'unit_of_measurement': 'W', + }), + 'context': , + 'entity_id': 'sensor.wifi_dual_meter_total_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.wifi_dual_meter_total_production-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.wifi_dual_meter_total_production', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Total production', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total production', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'total_production', + 'unique_id': 'tuya.lnjsbx45z3p7s59zbdnzreverse_energy_total', + 'unit_of_measurement': , + }) +# --- +# name: test_platform_setup_and_discovery[sensor.wifi_dual_meter_total_production-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'WIFI Dual Meter Total production', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.wifi_dual_meter_total_production', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- # name: test_platform_setup_and_discovery[sensor.wifi_smart_gas_boiler_thermostat_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -22385,6 +23764,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -22438,6 +23818,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -22491,6 +23872,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -22542,6 +23924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery state', 'options': dict({ }), 'original_device_class': None, @@ -22592,6 +23975,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -22645,6 +24029,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -22701,6 +24086,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -22754,6 +24140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -22810,6 +24197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -22866,6 +24254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Phase A voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -22922,6 +24311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply frequency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -22978,6 +24368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23034,6 +24425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23090,6 +24482,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total production', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23146,6 +24539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23205,6 +24599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -23261,6 +24656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ }), 'original_device_class': None, @@ -23312,6 +24708,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -23371,6 +24768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -23424,6 +24822,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -23480,6 +24879,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total dissolved solids', 'options': dict({ }), 'original_device_class': None, @@ -23532,6 +24932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -23591,6 +24992,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -23647,6 +25049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/tuya/snapshots/test_siren.ambr b/tests/components/tuya/snapshots/test_siren.ambr index c907d94dc39..2c774f0195f 100644 --- a/tests/components/tuya/snapshots/test_siren.ambr +++ b/tests/components/tuya/snapshots/test_siren.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_switch.ambr b/tests/components/tuya/snapshots/test_switch.ambr index 90b525ed432..dfc25504e06 100644 --- a/tests/components/tuya/snapshots/test_switch.ambr +++ b/tests/components/tuya/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 3', 'options': dict({ }), 'original_device_class': , @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 4', 'options': dict({ }), 'original_device_class': , @@ -313,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -361,6 +368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -410,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -459,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -507,6 +517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -556,6 +567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -605,6 +617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -653,6 +666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -702,6 +716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -750,6 +765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -799,6 +815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -847,6 +864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -896,6 +914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -945,6 +964,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -994,6 +1014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -1043,6 +1064,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -1092,6 +1114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -1141,6 +1164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -1189,6 +1213,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Snooze', 'options': dict({ }), 'original_device_class': None, @@ -1238,6 +1263,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -1286,6 +1312,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -1335,6 +1362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -1384,6 +1412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -1433,6 +1462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -1481,6 +1511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm', 'options': dict({ }), 'original_device_class': None, @@ -1529,6 +1560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion tracking', 'options': dict({ }), 'original_device_class': None, @@ -1577,6 +1609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Privacy mode', 'options': dict({ }), 'original_device_class': None, @@ -1625,6 +1658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound detection', 'options': dict({ }), 'original_device_class': None, @@ -1673,6 +1707,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -1721,6 +1756,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Video recording', 'options': dict({ }), 'original_device_class': None, @@ -1769,6 +1805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -1817,6 +1854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm', 'options': dict({ }), 'original_device_class': None, @@ -1865,6 +1903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion recording', 'options': dict({ }), 'original_device_class': None, @@ -1913,6 +1952,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion tracking', 'options': dict({ }), 'original_device_class': None, @@ -1961,6 +2001,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -2009,6 +2050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Video recording', 'options': dict({ }), 'original_device_class': None, @@ -2057,6 +2099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wide dynamic range', 'options': dict({ }), 'original_device_class': None, @@ -2105,6 +2148,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -2153,6 +2197,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm', 'options': dict({ }), 'original_device_class': None, @@ -2201,6 +2246,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound detection', 'options': dict({ }), 'original_device_class': None, @@ -2249,6 +2295,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -2297,6 +2344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Video recording', 'options': dict({ }), 'original_device_class': None, @@ -2345,6 +2393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -2393,6 +2442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm', 'options': dict({ }), 'original_device_class': None, @@ -2441,6 +2491,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound detection', 'options': dict({ }), 'original_device_class': None, @@ -2489,6 +2540,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -2537,6 +2589,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Video recording', 'options': dict({ }), 'original_device_class': None, @@ -2585,6 +2638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -2634,6 +2688,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power limit', 'options': dict({ }), 'original_device_class': None, @@ -2682,6 +2737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sound', 'options': dict({ }), 'original_device_class': None, @@ -2730,6 +2786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2778,6 +2835,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -2827,6 +2885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -2876,6 +2935,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -2925,6 +2985,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -2974,6 +3035,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3023,6 +3085,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3071,6 +3134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -3120,6 +3184,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3169,6 +3234,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter reset', 'options': dict({ }), 'original_device_class': None, @@ -3218,6 +3284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -3267,6 +3334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -3316,6 +3384,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -3365,6 +3434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3413,6 +3483,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -3461,6 +3532,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3509,6 +3581,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -3557,6 +3630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -3605,6 +3679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3653,6 +3728,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3701,6 +3777,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -3750,6 +3827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3798,6 +3876,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -3847,6 +3926,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3895,6 +3975,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -3944,6 +4025,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -3992,6 +4074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -4040,6 +4123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -4089,6 +4173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -4138,6 +4223,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -4187,6 +4273,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -4235,6 +4322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm', 'options': dict({ }), 'original_device_class': None, @@ -4283,6 +4371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion recording', 'options': dict({ }), 'original_device_class': None, @@ -4331,6 +4420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion tracking', 'options': dict({ }), 'original_device_class': None, @@ -4379,6 +4469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Privacy mode', 'options': dict({ }), 'original_device_class': None, @@ -4427,6 +4518,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -4475,6 +4567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Video recording', 'options': dict({ }), 'original_device_class': None, @@ -4523,6 +4616,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -4572,6 +4666,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -4621,6 +4716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -4669,6 +4765,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -4718,6 +4815,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -4766,6 +4864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -4814,6 +4913,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -4862,6 +4962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV sterilization', 'options': dict({ }), 'original_device_class': None, @@ -4910,6 +5011,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute', 'options': dict({ }), 'original_device_class': None, @@ -4958,6 +5060,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -5006,6 +5109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -5055,6 +5159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -5104,6 +5209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -5152,6 +5258,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -5201,6 +5308,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -5249,6 +5357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Motion alarm', 'options': dict({ }), 'original_device_class': None, @@ -5297,6 +5406,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -5345,6 +5455,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': None, @@ -5393,6 +5504,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': None, @@ -5441,6 +5553,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 3', 'options': dict({ }), 'original_device_class': None, @@ -5489,6 +5602,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 4', 'options': dict({ }), 'original_device_class': None, @@ -5537,6 +5651,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -5585,6 +5700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cartridge reset', 'options': dict({ }), 'original_device_class': None, @@ -5633,6 +5749,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -5681,6 +5798,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -5729,6 +5847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV sterilization', 'options': dict({ }), 'original_device_class': None, @@ -5756,6 +5875,56 @@ 'state': 'on', }) # --- +# name: test_platform_setup_and_discovery[switch.jardim_frontal_switch_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.jardim_frontal_switch_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Switch 1', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Switch 1', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_switch', + 'unique_id': 'tuya.xms6qowipdvjnkdgqdtswitch_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.jardim_frontal_switch_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'outlet', + 'friendly_name': 'Jardim frontal Switch 1', + }), + 'context': , + 'entity_id': 'switch.jardim_frontal_switch_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[switch.jardin_fraises_switch_1-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -5777,6 +5946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -5826,6 +5996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -5874,6 +6045,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -5923,6 +6095,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -5971,6 +6144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frost protection', 'options': dict({ }), 'original_device_class': None, @@ -6019,6 +6193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter cartridge reset', 'options': dict({ }), 'original_device_class': None, @@ -6067,6 +6242,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -6115,6 +6291,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto clean', 'options': dict({ }), 'original_device_class': None, @@ -6163,6 +6340,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -6212,6 +6390,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -6261,6 +6440,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 3', 'options': dict({ }), 'original_device_class': , @@ -6310,6 +6490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'USB 1', 'options': dict({ }), 'original_device_class': None, @@ -6358,6 +6539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep', 'options': dict({ }), 'original_device_class': None, @@ -6406,6 +6588,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -6454,6 +6637,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -6503,6 +6687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -6552,6 +6737,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -6601,6 +6787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -6650,6 +6837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -6699,6 +6887,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse', 'options': dict({ }), 'original_device_class': None, @@ -6747,6 +6936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -6795,6 +6985,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute', 'options': dict({ }), 'original_device_class': None, @@ -6843,6 +7034,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -6891,6 +7083,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flip', 'options': dict({ }), 'original_device_class': None, @@ -6939,6 +7132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time watermark', 'options': dict({ }), 'original_device_class': None, @@ -6987,6 +7181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Arm beep', 'options': dict({ }), 'original_device_class': None, @@ -7035,6 +7230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Siren', 'options': dict({ }), 'original_device_class': None, @@ -7083,6 +7279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -7132,6 +7329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -7180,6 +7378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -7229,6 +7428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -7278,6 +7478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -7326,6 +7527,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -7375,6 +7577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': , @@ -7424,6 +7627,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter reset', 'options': dict({ }), 'original_device_class': None, @@ -7472,6 +7676,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -7520,6 +7725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reset of water usage days', 'options': dict({ }), 'original_device_class': None, @@ -7568,6 +7774,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'UV sterilization', 'options': dict({ }), 'original_device_class': None, @@ -7616,6 +7823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pump reset', 'options': dict({ }), 'original_device_class': None, @@ -7664,6 +7872,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Do not disturb', 'options': dict({ }), 'original_device_class': None, @@ -7712,6 +7921,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto clean', 'options': dict({ }), 'original_device_class': None, @@ -7760,6 +7970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -7809,6 +8020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -7837,6 +8049,56 @@ 'state': 'off', }) # --- +# name: test_platform_setup_and_discovery[switch.puerta_casa_switch_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.puerta_casa_switch_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Switch 1', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Switch 1', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_switch', + 'unique_id': 'tuya.w9hdtm88xj5crtc1qdtswitch_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.puerta_casa_switch_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'outlet', + 'friendly_name': 'Puerta Casa Switch 1', + }), + 'context': , + 'entity_id': 'switch.puerta_casa_switch_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[switch.qt_switch_switch_1-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -7858,6 +8120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -7907,6 +8170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -7955,6 +8219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -8004,6 +8269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -8053,6 +8319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -8101,6 +8368,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -8150,6 +8418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -8199,6 +8468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -8247,6 +8517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -8296,6 +8567,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': , @@ -8345,6 +8617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 3', 'options': dict({ }), 'original_device_class': , @@ -8394,6 +8667,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 4', 'options': dict({ }), 'original_device_class': , @@ -8443,6 +8717,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 5', 'options': dict({ }), 'original_device_class': , @@ -8492,6 +8767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 6', 'options': dict({ }), 'original_device_class': , @@ -8541,6 +8817,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -8589,6 +8866,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -8617,6 +8895,56 @@ 'state': 'on', }) # --- +# name: test_platform_setup_and_discovery[switch.server_fan_switch_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.server_fan_switch_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Switch 1', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Switch 1', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_switch', + 'unique_id': 'tuya.cxbmhihohohk5bmeqdtswitch_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.server_fan_switch_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'outlet', + 'friendly_name': 'Server Fan Switch 1', + }), + 'context': , + 'entity_id': 'switch.server_fan_switch_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_platform_setup_and_discovery[switch.signal_repeater_socket_1-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -8638,6 +8966,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -8687,6 +9016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -8735,6 +9065,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': None, @@ -8783,6 +9114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 2', 'options': dict({ }), 'original_device_class': None, @@ -8831,6 +9163,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -8879,6 +9212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frost protection', 'options': dict({ }), 'original_device_class': None, @@ -8927,6 +9261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -8975,6 +9310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Music', 'options': dict({ }), 'original_device_class': None, @@ -9024,6 +9360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute', 'options': dict({ }), 'original_device_class': None, @@ -9072,6 +9409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute', 'options': dict({ }), 'original_device_class': None, @@ -9120,6 +9458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': , @@ -9169,6 +9508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -9217,6 +9557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -9266,6 +9607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -9315,6 +9657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy saving', 'options': dict({ }), 'original_device_class': None, @@ -9363,6 +9706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start', 'options': dict({ }), 'original_device_class': None, @@ -9411,6 +9755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -9460,6 +9805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -9508,6 +9854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -9557,6 +9904,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -9606,6 +9954,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -9655,6 +10004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': , @@ -9705,6 +10055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preheat', 'options': dict({ }), 'original_device_class': , @@ -9755,6 +10106,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side A Power', 'options': dict({ }), 'original_device_class': , @@ -9805,6 +10157,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side A Preheat', 'options': dict({ }), 'original_device_class': , @@ -9855,6 +10208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side B Power', 'options': dict({ }), 'original_device_class': , @@ -9905,6 +10259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side B Preheat', 'options': dict({ }), 'original_device_class': , @@ -9955,6 +10310,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -10003,6 +10359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -10052,6 +10409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 2', 'options': dict({ }), 'original_device_class': , @@ -10101,6 +10459,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ionizer', 'options': dict({ }), 'original_device_class': None, @@ -10149,6 +10508,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Do not disturb', 'options': dict({ }), 'original_device_class': None, @@ -10197,6 +10557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -10246,6 +10607,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -10294,6 +10656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -10343,6 +10706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , @@ -10392,6 +10756,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter reset', 'options': dict({ }), 'original_device_class': None, @@ -10440,6 +10805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ }), 'original_device_class': None, @@ -10488,6 +10854,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pump reset', 'options': dict({ }), 'original_device_class': None, @@ -10536,6 +10903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -10585,6 +10953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -10633,6 +11002,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket 1', 'options': dict({ }), 'original_device_class': , @@ -10682,6 +11052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -10730,6 +11101,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Music', 'options': dict({ }), 'original_device_class': None, @@ -10779,6 +11151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -10827,6 +11200,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frost protection', 'options': dict({ }), 'original_device_class': None, @@ -10875,6 +11249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mute', 'options': dict({ }), 'original_device_class': None, @@ -10923,6 +11298,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -10971,6 +11347,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -11019,6 +11396,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch', 'options': dict({ }), 'original_device_class': None, @@ -11067,6 +11445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Socket', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/tuya/snapshots/test_vacuum.ambr b/tests/components/tuya/snapshots/test_vacuum.ambr index 74ffb6df720..907fd7c2878 100644 --- a/tests/components/tuya/snapshots/test_vacuum.ambr +++ b/tests/components/tuya/snapshots/test_vacuum.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/tuya/snapshots/test_valve.ambr b/tests/components/tuya/snapshots/test_valve.ambr index 55d42dc56a2..a0d69ffcd86 100644 --- a/tests/components/tuya/snapshots/test_valve.ambr +++ b/tests/components/tuya/snapshots/test_valve.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 1', 'options': dict({ }), 'original_device_class': , @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 2', 'options': dict({ }), 'original_device_class': , @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 3', 'options': dict({ }), 'original_device_class': , @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 4', 'options': dict({ }), 'original_device_class': , @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 5', 'options': dict({ }), 'original_device_class': , @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 6', 'options': dict({ }), 'original_device_class': , @@ -420,6 +428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 7', 'options': dict({ }), 'original_device_class': , @@ -470,6 +479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve 8', 'options': dict({ }), 'original_device_class': , @@ -520,6 +530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , @@ -570,6 +581,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , @@ -620,6 +632,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/twentemilieu/snapshots/test_calendar.ambr b/tests/components/twentemilieu/snapshots/test_calendar.ambr index 15fcd7cee09..ee96494871f 100644 --- a/tests/components/twentemilieu/snapshots/test_calendar.ambr +++ b/tests/components/twentemilieu/snapshots/test_calendar.ambr @@ -65,6 +65,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/twentemilieu/snapshots/test_sensor.ambr b/tests/components/twentemilieu/snapshots/test_sensor.ambr index 3b4e21be1e1..4ca1dde3f1a 100644 --- a/tests/components/twentemilieu/snapshots/test_sensor.ambr +++ b/tests/components/twentemilieu/snapshots/test_sensor.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Christmas tree pickup', 'options': dict({ }), 'original_device_class': , @@ -114,6 +115,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Non-recyclable waste pickup', 'options': dict({ }), 'original_device_class': , @@ -194,6 +196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Organic waste pickup', 'options': dict({ }), 'original_device_class': , @@ -274,6 +277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Packages waste pickup', 'options': dict({ }), 'original_device_class': , @@ -354,6 +358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Paper waste pickup', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/twinkly/snapshots/test_light.ambr b/tests/components/twinkly/snapshots/test_light.ambr index 5b5137d2b73..91e85e18e2a 100644 --- a/tests/components/twinkly/snapshots/test_light.ambr +++ b/tests/components/twinkly/snapshots/test_light.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/twinkly/snapshots/test_select.ambr b/tests/components/twinkly/snapshots/test_select.ambr index 58d796ea2e4..4e05d27fc60 100644 --- a/tests/components/twinkly/snapshots/test_select.ambr +++ b/tests/components/twinkly/snapshots/test_select.ambr @@ -30,6 +30,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mode', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/unifi/snapshots/test_button.ambr b/tests/components/unifi/snapshots/test_button.ambr index b0fbe9cdbb8..a573abdeb45 100644 --- a/tests/components/unifi/snapshots/test_button.ambr +++ b/tests/components/unifi/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Regenerate Password', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 Power Cycle', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/unifi/snapshots/test_device_tracker.ambr b/tests/components/unifi/snapshots/test_device_tracker.ambr index 2a8af0dd765..a2e5155b0ea 100644 --- a/tests/components/unifi/snapshots/test_device_tracker.ambr +++ b/tests/components/unifi/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Switch 1', 'options': dict({ }), 'original_device_class': None, @@ -71,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'wd_client_1', 'options': dict({ }), 'original_device_class': None, @@ -122,6 +124,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ws_client_1', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/unifi/snapshots/test_image.ambr b/tests/components/unifi/snapshots/test_image.ambr index d27e9ade3aa..9ca30ba8ec0 100644 --- a/tests/components/unifi/snapshots/test_image.ambr +++ b/tests/components/unifi/snapshots/test_image.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'QR Code', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/unifi/snapshots/test_light.ambr b/tests/components/unifi/snapshots/test_light.ambr index 7e5e152dd46..04ba5c79acc 100644 --- a/tests/components/unifi/snapshots/test_light.ambr +++ b/tests/components/unifi/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/unifi/snapshots/test_sensor.ambr b/tests/components/unifi/snapshots/test_sensor.ambr index a925b29748e..cceb485e7da 100644 --- a/tests/components/unifi/snapshots/test_sensor.ambr +++ b/tests/components/unifi/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clients', 'options': dict({ }), 'original_device_class': None, @@ -86,6 +87,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -149,6 +151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -253,6 +257,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC Power Budget', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -309,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC Power Consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -365,6 +371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clients', 'options': dict({ }), 'original_device_class': None, @@ -416,6 +423,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU utilization', 'options': dict({ }), 'original_device_class': None, @@ -468,6 +476,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory utilization', 'options': dict({ }), 'original_device_class': None, @@ -520,6 +529,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outlet 2 Outlet Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -589,6 +599,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -652,6 +663,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -703,6 +715,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Clients', 'options': dict({ }), 'original_device_class': None, @@ -754,6 +767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloudflare WAN2 latency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -810,6 +824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cloudflare WAN latency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -866,6 +881,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Google WAN2 latency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -922,6 +938,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Google WAN latency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -978,6 +995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Microsoft WAN2 latency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1034,6 +1052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Microsoft WAN latency', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1090,6 +1109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 PoE Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1146,6 +1166,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1205,6 +1226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1264,6 +1286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2 PoE Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1320,6 +1343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2 RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1379,6 +1403,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2 TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1438,6 +1463,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 3 RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1497,6 +1523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 3 TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1556,6 +1583,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4 PoE Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1612,6 +1640,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4 RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1671,6 +1700,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4 TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1743,6 +1773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -1806,6 +1837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -1857,6 +1889,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -1908,6 +1941,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Link speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1964,6 +1998,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2020,6 +2055,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2074,6 +2110,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -2125,6 +2162,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2181,6 +2219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'TX', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2235,6 +2274,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/unifi/snapshots/test_switch.ambr b/tests/components/unifi/snapshots/test_switch.ambr index 4fabff5d278..e02bda89d4a 100644 --- a/tests/components/unifi/snapshots/test_switch.ambr +++ b/tests/components/unifi/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Block Media Streaming', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outlet 2', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'USB Outlet 1', 'options': dict({ }), 'original_device_class': , @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1', 'options': dict({ }), 'original_device_class': , @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 1 PoE', 'options': dict({ }), 'original_device_class': , @@ -313,6 +319,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2', 'options': dict({ }), 'original_device_class': , @@ -362,6 +369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 2 PoE', 'options': dict({ }), 'original_device_class': , @@ -411,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 3', 'options': dict({ }), 'original_device_class': , @@ -460,6 +469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4', 'options': dict({ }), 'original_device_class': , @@ -509,6 +519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Port 4 PoE', 'options': dict({ }), 'original_device_class': , @@ -558,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outlet 1', 'options': dict({ }), 'original_device_class': , @@ -607,6 +619,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -656,6 +669,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'plex', 'options': dict({ }), 'original_device_class': , @@ -705,6 +719,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test Traffic Rule', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/unifi/snapshots/test_update.ambr b/tests/components/unifi/snapshots/test_update.ambr index caa23768857..a14470b8f8b 100644 --- a/tests/components/unifi/snapshots/test_update.ambr +++ b/tests/components/unifi/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -142,6 +144,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -203,6 +206,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/unifiprotect/test_number.py b/tests/components/unifiprotect/test_number.py index d308d0199d7..7ccb1705964 100644 --- a/tests/components/unifiprotect/test_number.py +++ b/tests/components/unifiprotect/test_number.py @@ -3,10 +3,10 @@ from __future__ import annotations from datetime import timedelta -from unittest.mock import AsyncMock +from unittest.mock import AsyncMock, Mock import pytest -from uiprotect.data import Camera, Doorlock, IRLEDMode, Light +from uiprotect.data import Camera, Chime, Doorlock, IRLEDMode, Light, RingSetting from homeassistant.components.unifiprotect.const import DEFAULT_ATTRIBUTION from homeassistant.components.unifiprotect.number import ( @@ -264,3 +264,140 @@ async def test_number_lock_auto_close( ) mock_method.assert_called_once_with(timedelta(seconds=15.0)) + + +def _setup_chime_with_doorbell( + chime: Chime, doorbell: Camera, volume: int = 50 +) -> None: + """Set up chime with paired doorbell for testing.""" + chime.camera_ids = [doorbell.id] + chime.ring_settings = [ + RingSetting( + camera_id=doorbell.id, + repeat_times=1, + ringtone_id="test-ringtone-id", + volume=volume, + ) + ] + + +async def test_chime_ring_volume_setup( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + ufp: MockUFPFixture, + chime: Chime, + doorbell: Camera, +) -> None: + """Test chime ring volume number entity setup.""" + _setup_chime_with_doorbell(chime, doorbell, volume=75) + + await init_entry(hass, ufp, [chime, doorbell], regenerate_ids=False) + + entity_id = "number.test_chime_ring_volume_test_camera" + entity = entity_registry.async_get(entity_id) + assert entity is not None + assert entity.unique_id == f"{chime.mac}_ring_volume_{doorbell.id}" + + state = hass.states.get(entity_id) + assert state is not None + assert state.state == "75" + assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION + + +async def test_chime_ring_volume_set_value( + hass: HomeAssistant, + ufp: MockUFPFixture, + chime: Chime, + doorbell: Camera, +) -> None: + """Test setting chime ring volume.""" + _setup_chime_with_doorbell(chime, doorbell) + + await init_entry(hass, ufp, [chime, doorbell], regenerate_ids=False) + + entity_id = "number.test_chime_ring_volume_test_camera" + + with patch_ufp_method( + chime, "set_volume_for_camera_public", new_callable=AsyncMock + ) as mock_method: + await hass.services.async_call( + "number", + "set_value", + {ATTR_ENTITY_ID: entity_id, "value": 80.0}, + blocking=True, + ) + + mock_method.assert_called_once_with(doorbell, 80) + + +async def test_chime_ring_volume_multiple_cameras( + hass: HomeAssistant, + ufp: MockUFPFixture, + chime: Chime, + doorbell: Camera, +) -> None: + """Test chime ring volume with multiple paired cameras.""" + doorbell2 = doorbell.model_copy() + doorbell2.id = "test-doorbell-2" + doorbell2.name = "Test Doorbell 2" + doorbell2.mac = "aa:bb:cc:dd:ee:02" + + chime.camera_ids = [doorbell.id, doorbell2.id] + chime.ring_settings = [ + RingSetting( + camera_id=doorbell.id, + repeat_times=1, + ringtone_id="test-ringtone-id", + volume=60, + ), + RingSetting( + camera_id=doorbell2.id, + repeat_times=2, + ringtone_id="test-ringtone-id-2", + volume=80, + ), + ] + + await init_entry(hass, ufp, [chime, doorbell, doorbell2], regenerate_ids=False) + + state1 = hass.states.get("number.test_chime_ring_volume_test_camera") + assert state1 is not None + assert state1.state == "60" + + state2 = hass.states.get("number.test_chime_ring_volume_test_doorbell_2") + assert state2 is not None + assert state2.state == "80" + + +async def test_chime_ring_volume_unavailable_when_unpaired( + hass: HomeAssistant, + ufp: MockUFPFixture, + chime: Chime, + doorbell: Camera, +) -> None: + """Test chime ring volume becomes unavailable when camera is unpaired.""" + _setup_chime_with_doorbell(chime, doorbell) + + await init_entry(hass, ufp, [chime, doorbell], regenerate_ids=False) + + entity_id = "number.test_chime_ring_volume_test_camera" + state = hass.states.get(entity_id) + assert state + assert state.state == "50" + + # Simulate removing the camera pairing + new_chime = chime.model_copy() + new_chime.ring_settings = [] + + ufp.api.bootstrap.chimes = {new_chime.id: new_chime} + ufp.api.bootstrap.nvr.system_info.ustorage = None + mock_msg = Mock() + mock_msg.changed_data = {} + mock_msg.new_obj = new_chime + + ufp.ws_msg(mock_msg) + await hass.async_block_till_done() + + state = hass.states.get(entity_id) + assert state + assert state.state == "unavailable" diff --git a/tests/components/unifiprotect/test_services.py b/tests/components/unifiprotect/test_services.py index f08e7157b83..23db8df4fe6 100644 --- a/tests/components/unifiprotect/test_services.py +++ b/tests/components/unifiprotect/test_services.py @@ -260,7 +260,6 @@ async def test_remove_privacy_zone( assert not doorbell.privacy_zones -@pytest.mark.asyncio async def get_user_keyring_info( hass: HomeAssistant, entity_registry: er.EntityRegistry, diff --git a/tests/components/update/test_device_trigger.py b/tests/components/update/test_device_trigger.py index 7cdaf4ca720..bb6ad4106bf 100644 --- a/tests/components/update/test_device_trigger.py +++ b/tests/components/update/test_device_trigger.py @@ -25,11 +25,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/update/test_trigger.py b/tests/components/update/test_trigger.py index 1e85778f923..87615bb61b0 100644 --- a/tests/components/update/test_trigger.py +++ b/tests/components/update/test_trigger.py @@ -1,8 +1,6 @@ """Test update triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, STATE_OFF, STATE_ from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, parametrize_target_entities, parametrize_trigger_states, @@ -20,21 +18,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_updates(hass: HomeAssistant) -> list[str]: """Create multiple update entities associated with different targets.""" @@ -60,7 +43,7 @@ async def test_update_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -84,7 +67,7 @@ async def test_update_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the update state trigger fires when any update state changes to a specific state.""" other_entity_ids = set(target_updates) - {entity_id} @@ -113,7 +96,7 @@ async def test_update_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -137,7 +120,7 @@ async def test_update_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the update state trigger fires when the first update changes to a specific state.""" other_entity_ids = set(target_updates) - {entity_id} @@ -165,7 +148,7 @@ async def test_update_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities(DOMAIN), @@ -189,7 +172,7 @@ async def test_update_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the update state trigger fires when the last update changes to a specific state.""" other_entity_ids = set(target_updates) - {entity_id} diff --git a/tests/components/uptime/snapshots/test_sensor.ambr b/tests/components/uptime/snapshots/test_sensor.ambr index c57f2987c5b..1a2ef2eeb3a 100644 --- a/tests/components/uptime/snapshots/test_sensor.ambr +++ b/tests/components/uptime/snapshots/test_sensor.ambr @@ -34,6 +34,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/uptime_kuma/snapshots/test_sensor.ambr b/tests/components/uptime_kuma/snapshots/test_sensor.ambr index 49a7d141c47..f59cd675b44 100644 --- a/tests/components/uptime_kuma/snapshots/test_sensor.ambr +++ b/tests/components/uptime_kuma/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Certificate expiry', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -103,6 +104,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitor type', 'options': dict({ }), 'original_device_class': , @@ -181,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitored URL', 'options': dict({ }), 'original_device_class': None, @@ -229,6 +232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Response time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -289,6 +293,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -374,6 +379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitor type', 'options': dict({ }), 'original_device_class': , @@ -452,6 +458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitored hostname', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +507,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitored port', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +556,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Response time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -608,6 +617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -663,6 +673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Certificate expiry', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -746,6 +757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitor type', 'options': dict({ }), 'original_device_class': , @@ -824,6 +836,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Monitored URL', 'options': dict({ }), 'original_device_class': None, @@ -872,6 +885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Response time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -932,6 +946,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/uptime_kuma/snapshots/test_update.ambr b/tests/components/uptime_kuma/snapshots/test_update.ambr index 225584a5181..1080be61ab9 100644 --- a/tests/components/uptime_kuma/snapshots/test_update.ambr +++ b/tests/components/uptime_kuma/snapshots/test_update.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime Kuma version', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/v2c/snapshots/test_sensor.ambr b/tests/components/v2c/snapshots/test_sensor.ambr index 3ff711383d7..a91a4445592 100644 --- a/tests/components/v2c/snapshots/test_sensor.ambr +++ b/tests/components/v2c/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charge time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'House power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Installation voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -356,6 +362,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IP address', 'options': dict({ }), 'original_device_class': None, @@ -442,6 +449,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter error', 'options': dict({ }), 'original_device_class': , @@ -530,6 +538,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Photovoltaic power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -586,6 +595,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal status', 'options': dict({ }), 'original_device_class': None, @@ -635,6 +645,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SSID', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vacuum/test_device_action.py b/tests/components/vacuum/test_device_action.py index 08459e05571..16eed849439 100644 --- a/tests/components/vacuum/test_device_action.py +++ b/tests/components/vacuum/test_device_action.py @@ -19,11 +19,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/vacuum/test_device_condition.py b/tests/components/vacuum/test_device_condition.py index 5a1b1fea7de..028998b6d14 100644 --- a/tests/components/vacuum/test_device_condition.py +++ b/tests/components/vacuum/test_device_condition.py @@ -15,11 +15,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_conditions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/vacuum/test_device_trigger.py b/tests/components/vacuum/test_device_trigger.py index 330f14be507..7a51c7caee6 100644 --- a/tests/components/vacuum/test_device_trigger.py +++ b/tests/components/vacuum/test_device_trigger.py @@ -23,11 +23,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_triggers( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/vacuum/test_trigger.py b/tests/components/vacuum/test_trigger.py index 343eca399d9..7c71346cc4e 100644 --- a/tests/components/vacuum/test_trigger.py +++ b/tests/components/vacuum/test_trigger.py @@ -1,8 +1,6 @@ """Test vacuum triggers.""" -from collections.abc import Generator from typing import Any -from unittest.mock import patch import pytest @@ -11,7 +9,7 @@ from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID from homeassistant.core import HomeAssistant, ServiceCall from tests.components import ( - StateDescription, + TriggerStateDescription, arm_trigger, other_states, parametrize_target_entities, @@ -21,21 +19,6 @@ from tests.components import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture async def target_vacuums(hass: HomeAssistant) -> list[str]: """Create multiple vacuum entities associated with different targets.""" @@ -49,6 +32,7 @@ async def target_vacuums(hass: HomeAssistant) -> list[str]: "vacuum.errored", "vacuum.paused_cleaning", "vacuum.started_cleaning", + "vacuum.started_returning", ], ) async def test_vacuum_triggers_gated_by_labs_flag( @@ -64,7 +48,7 @@ async def test_vacuum_triggers_gated_by_labs_flag( ) in caplog.text -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("vacuum"), @@ -92,6 +76,11 @@ async def test_vacuum_triggers_gated_by_labs_flag( target_states=[VacuumActivity.CLEANING], other_states=other_states(VacuumActivity.CLEANING), ), + *parametrize_trigger_states( + trigger="vacuum.started_returning", + target_states=[VacuumActivity.RETURNING], + other_states=other_states(VacuumActivity.RETURNING), + ), ], ) async def test_vacuum_state_trigger_behavior_any( @@ -103,7 +92,7 @@ async def test_vacuum_state_trigger_behavior_any( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the vacuum state trigger fires when any vacuum state changes to a specific state.""" other_entity_ids = set(target_vacuums) - {entity_id} @@ -132,7 +121,7 @@ async def test_vacuum_state_trigger_behavior_any( service_calls.clear() -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("vacuum"), @@ -160,6 +149,11 @@ async def test_vacuum_state_trigger_behavior_any( target_states=[VacuumActivity.CLEANING], other_states=other_states(VacuumActivity.CLEANING), ), + *parametrize_trigger_states( + trigger="vacuum.started_returning", + target_states=[VacuumActivity.RETURNING], + other_states=other_states(VacuumActivity.RETURNING), + ), ], ) async def test_vacuum_state_trigger_behavior_first( @@ -171,7 +165,7 @@ async def test_vacuum_state_trigger_behavior_first( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the vacuum state trigger fires when the first vacuum changes to a specific state.""" other_entity_ids = set(target_vacuums) - {entity_id} @@ -199,7 +193,7 @@ async def test_vacuum_state_trigger_behavior_first( assert len(service_calls) == 0 -@pytest.mark.usefixtures("enable_experimental_triggers_conditions") +@pytest.mark.usefixtures("enable_labs_preview_features") @pytest.mark.parametrize( ("trigger_target_config", "entity_id", "entities_in_target"), parametrize_target_entities("vacuum"), @@ -227,6 +221,11 @@ async def test_vacuum_state_trigger_behavior_first( target_states=[VacuumActivity.CLEANING], other_states=other_states(VacuumActivity.CLEANING), ), + *parametrize_trigger_states( + trigger="vacuum.started_returning", + target_states=[VacuumActivity.RETURNING], + other_states=other_states(VacuumActivity.RETURNING), + ), ], ) async def test_vacuum_state_trigger_behavior_last( @@ -238,7 +237,7 @@ async def test_vacuum_state_trigger_behavior_last( entities_in_target: int, trigger: str, trigger_options: dict[str, Any], - states: list[StateDescription], + states: list[TriggerStateDescription], ) -> None: """Test that the vacuum state trigger fires when the last vacuum changes to a specific state.""" other_entity_ids = set(target_vacuums) - {entity_id} diff --git a/tests/components/vegehub/snapshots/test_sensor.ambr b/tests/components/vegehub/snapshots/test_sensor.ambr index 6fb0ef67c50..d1eca09465e 100644 --- a/tests/components/vegehub/snapshots/test_sensor.ambr +++ b/tests/components/vegehub/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -126,6 +128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -179,6 +182,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -232,6 +236,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input 4', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/vegehub/snapshots/test_switch.ambr b/tests/components/vegehub/snapshots/test_switch.ambr index ea6d0f81791..8ca3dafa009 100644 --- a/tests/components/vegehub/snapshots/test_switch.ambr +++ b/tests/components/vegehub/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actuator 1', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Actuator 2', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/velbus/snapshots/test_binary_sensor.ambr b/tests/components/velbus/snapshots/test_binary_sensor.ambr index 6ba8ad096c0..aea7de6c0d4 100644 --- a/tests/components/velbus/snapshots/test_binary_sensor.ambr +++ b/tests/components/velbus/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ButtonOn', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velbus/snapshots/test_button.ambr b/tests/components/velbus/snapshots/test_button.ambr index 7b06cbfb548..287e005227c 100644 --- a/tests/components/velbus/snapshots/test_button.ambr +++ b/tests/components/velbus/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ButtonOn', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velbus/snapshots/test_climate.ambr b/tests/components/velbus/snapshots/test_climate.ambr index 027f06c3858..fc802c43d06 100644 --- a/tests/components/velbus/snapshots/test_climate.ambr +++ b/tests/components/velbus/snapshots/test_climate.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velbus/snapshots/test_cover.ambr b/tests/components/velbus/snapshots/test_cover.ambr index 53b6c921e23..6c211f903f0 100644 --- a/tests/components/velbus/snapshots/test_cover.ambr +++ b/tests/components/velbus/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CoverName', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CoverNameNoPos', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velbus/snapshots/test_light.ambr b/tests/components/velbus/snapshots/test_light.ambr index 0df4d06c590..c2ee3a9098d 100644 --- a/tests/components/velbus/snapshots/test_light.ambr +++ b/tests/components/velbus/snapshots/test_light.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED ButtonOn', 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dimmer', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velbus/snapshots/test_select.ambr b/tests/components/velbus/snapshots/test_select.ambr index 2e03a9da517..c2a744923ac 100644 --- a/tests/components/velbus/snapshots/test_select.ambr +++ b/tests/components/velbus/snapshots/test_select.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'select', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velbus/snapshots/test_sensor.ambr b/tests/components/velbus/snapshots/test_sensor.ambr index dc79663865f..37ad4ebac03 100644 --- a/tests/components/velbus/snapshots/test_sensor.ambr +++ b/tests/components/velbus/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ButtonCounter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'ButtonCounter-counter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -135,6 +137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LightSensor', 'options': dict({ }), 'original_device_class': None, @@ -187,6 +190,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SensorNumber', 'options': dict({ }), 'original_device_class': None, @@ -239,6 +243,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/velbus/snapshots/test_switch.ambr b/tests/components/velbus/snapshots/test_switch.ambr index 25551ed9071..d3be5a46a27 100644 --- a/tests/components/velbus/snapshots/test_switch.ambr +++ b/tests/components/velbus/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RelayName', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RelayName', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/velux/snapshots/test_button.ambr b/tests/components/velux/snapshots/test_button.ambr index c77f8ed2315..910c1e64162 100644 --- a/tests/components/velux/snapshots/test_button.ambr +++ b/tests/components/velux/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/velux/snapshots/test_cover.ambr b/tests/components/velux/snapshots/test_cover.ambr index 498bacd93fb..e6e9fa5f4f7 100644 --- a/tests/components/velux/snapshots/test_cover.ambr +++ b/tests/components/velux/snapshots/test_cover.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -123,6 +125,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -174,6 +177,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -225,6 +229,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -276,6 +281,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/velux/snapshots/test_scene.ambr b/tests/components/velux/snapshots/test_scene.ambr index 5884515b91b..813325d74de 100644 --- a/tests/components/velux/snapshots/test_scene.ambr +++ b/tests/components/velux/snapshots/test_scene.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Test Scene', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vesync/snapshots/test_binary_sensor.ambr b/tests/components/vesync/snapshots/test_binary_sensor.ambr index 1cd1f350481..66c9d95d9fe 100644 --- a/tests/components/vesync/snapshots/test_binary_sensor.ambr +++ b/tests/components/vesync/snapshots/test_binary_sensor.ambr @@ -378,6 +378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low water', 'options': dict({ }), 'original_device_class': , @@ -411,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water tank lifted', 'options': dict({ }), 'original_device_class': , @@ -509,6 +511,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low water', 'options': dict({ }), 'original_device_class': , @@ -542,6 +545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water tank lifted', 'options': dict({ }), 'original_device_class': , @@ -640,6 +644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low water', 'options': dict({ }), 'original_device_class': , @@ -673,6 +678,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water tank lifted', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vesync/snapshots/test_fan.ambr b/tests/components/vesync/snapshots/test_fan.ambr index eef8b54c0cd..4a820ea7b57 100644 --- a/tests/components/vesync/snapshots/test_fan.ambr +++ b/tests/components/vesync/snapshots/test_fan.ambr @@ -59,6 +59,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -157,6 +158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -257,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -358,6 +361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -757,6 +761,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vesync/snapshots/test_humidifier.ambr b/tests/components/vesync/snapshots/test_humidifier.ambr index 05ed0c6a236..d5a1b2dd36c 100644 --- a/tests/components/vesync/snapshots/test_humidifier.ambr +++ b/tests/components/vesync/snapshots/test_humidifier.ambr @@ -357,6 +357,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -459,6 +460,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -562,6 +564,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vesync/snapshots/test_light.ambr b/tests/components/vesync/snapshots/test_light.ambr index bb8358d605e..ae1b5529ed2 100644 --- a/tests/components/vesync/snapshots/test_light.ambr +++ b/tests/components/vesync/snapshots/test_light.ambr @@ -280,6 +280,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -371,6 +372,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -653,6 +655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vesync/snapshots/test_sensor.ambr b/tests/components/vesync/snapshots/test_sensor.ambr index 9a34b86517d..a0052ba6076 100644 --- a/tests/components/vesync/snapshots/test_sensor.ambr +++ b/tests/components/vesync/snapshots/test_sensor.ambr @@ -54,6 +54,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -89,6 +90,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -189,6 +191,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -274,6 +277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -309,6 +313,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -344,6 +349,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -458,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality', 'options': dict({ }), 'original_device_class': None, @@ -493,6 +500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -528,6 +536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -682,6 +692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking set temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -718,6 +729,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking set time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -754,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preheating set time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -801,6 +814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking status', 'options': dict({ }), 'original_device_class': , @@ -959,6 +973,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current temperature', 'options': dict({ }), 'original_device_class': , @@ -994,6 +1009,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking set temperature', 'options': dict({ }), 'original_device_class': , @@ -1027,6 +1043,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking set time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1063,6 +1080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preheating set time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1110,6 +1128,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cooking status', 'options': dict({ }), 'original_device_class': , @@ -1340,6 +1359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1428,6 +1448,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1463,6 +1484,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1501,6 +1523,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter lifetime', 'options': dict({ }), 'original_device_class': None, @@ -1620,6 +1643,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -1708,6 +1732,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy use today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1746,6 +1771,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy use weekly', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1784,6 +1810,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy use monthly', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1822,6 +1849,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy use yearly', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1860,6 +1888,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1898,6 +1927,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/vesync/snapshots/test_switch.ambr b/tests/components/vesync/snapshots/test_switch.ambr index 7dad568e8ed..f5d3d5cef80 100644 --- a/tests/components/vesync/snapshots/test_switch.ambr +++ b/tests/components/vesync/snapshots/test_switch.ambr @@ -54,6 +54,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -137,6 +138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -266,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -299,6 +303,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -395,6 +400,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -428,6 +434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -672,6 +679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -705,6 +713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto Off', 'options': dict({ }), 'original_device_class': None, @@ -801,6 +810,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -834,6 +844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child lock', 'options': dict({ }), 'original_device_class': None, @@ -867,6 +878,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto Off', 'options': dict({ }), 'original_device_class': None, @@ -976,6 +988,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -1009,6 +1022,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Auto Off', 'options': dict({ }), 'original_device_class': None, @@ -1105,6 +1119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -1189,6 +1204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Display', 'options': dict({ }), 'original_device_class': None, @@ -1309,6 +1325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vesync/snapshots/test_update.ambr b/tests/components/vesync/snapshots/test_update.ambr index bc5f9a68bc3..4a8a8599a4c 100644 --- a/tests/components/vesync/snapshots/test_update.ambr +++ b/tests/components/vesync/snapshots/test_update.ambr @@ -54,6 +54,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -150,6 +151,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -246,6 +248,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -342,6 +345,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -438,6 +442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -534,6 +539,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -630,6 +636,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -716,6 +723,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -812,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -908,6 +917,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1004,6 +1014,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1100,6 +1111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1196,6 +1208,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1292,6 +1305,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , @@ -1388,6 +1402,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vicare/snapshots/test_binary_sensor.ambr b/tests/components/vicare/snapshots/test_binary_sensor.ambr index 32e97b6e632..52cf00589f8 100644 --- a/tests/components/vicare/snapshots/test_binary_sensor.ambr +++ b/tests/components/vicare/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Circulation pump', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Circulation pump', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW charging', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW circulation pump', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW pump', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frost protection', 'options': dict({ }), 'original_device_class': None, @@ -362,6 +369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frost protection', 'options': dict({ }), 'original_device_class': None, @@ -410,6 +418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'One-time charge', 'options': dict({ }), 'original_device_class': , @@ -459,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Child safety lock', 'options': dict({ }), 'original_device_class': None, @@ -507,6 +517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identification mode', 'options': dict({ }), 'original_device_class': None, @@ -555,6 +566,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Mounting mode', 'options': dict({ }), 'original_device_class': None, @@ -603,6 +615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , @@ -652,6 +665,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identification mode', 'options': dict({ }), 'original_device_class': None, @@ -700,6 +714,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Identification mode', 'options': dict({ }), 'original_device_class': None, @@ -748,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vicare/snapshots/test_button.ambr b/tests/components/vicare/snapshots/test_button.ambr index c1026e48b7f..f6505aa7b44 100644 --- a/tests/components/vicare/snapshots/test_button.ambr +++ b/tests/components/vicare/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Activate one-time charge', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Deactivate one-time charge', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vicare/snapshots/test_climate.ambr b/tests/components/vicare/snapshots/test_climate.ambr index e2d8dab873e..8e87ca64348 100644 --- a/tests/components/vicare/snapshots/test_climate.ambr +++ b/tests/components/vicare/snapshots/test_climate.ambr @@ -32,6 +32,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vicare/snapshots/test_fan.ambr b/tests/components/vicare/snapshots/test_fan.ambr index e6f494c0fd1..0c586864ed3 100644 --- a/tests/components/vicare/snapshots/test_fan.ambr +++ b/tests/components/vicare/snapshots/test_fan.ambr @@ -27,6 +27,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation', 'options': dict({ }), 'original_device_class': None, @@ -97,6 +98,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vicare/snapshots/test_number.ambr b/tests/components/vicare/snapshots/test_number.ambr index 8a271d5d0f4..463354f73b9 100644 --- a/tests/components/vicare/snapshots/test_number.ambr +++ b/tests/components/vicare/snapshots/test_number.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Comfort temperature', 'options': dict({ }), 'original_device_class': , @@ -84,6 +85,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Comfort temperature', 'options': dict({ }), 'original_device_class': , @@ -143,6 +145,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW temperature', 'options': dict({ }), 'original_device_class': , @@ -202,6 +205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating curve shift', 'options': dict({ }), 'original_device_class': , @@ -261,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating curve shift', 'options': dict({ }), 'original_device_class': , @@ -320,6 +325,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating curve slope', 'options': dict({ }), 'original_device_class': None, @@ -377,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating curve slope', 'options': dict({ }), 'original_device_class': None, @@ -434,6 +441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Normal temperature', 'options': dict({ }), 'original_device_class': , @@ -493,6 +501,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Normal temperature', 'options': dict({ }), 'original_device_class': , @@ -552,6 +561,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reduced temperature', 'options': dict({ }), 'original_device_class': , @@ -611,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reduced temperature', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vicare/snapshots/test_sensor.ambr b/tests/components/vicare/snapshots/test_sensor.ambr index bf16b3c32b8..1956b3caea1 100644 --- a/tests/components/vicare/snapshots/test_sensor.ambr +++ b/tests/components/vicare/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boiler temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner hours', 'options': dict({ }), 'original_device_class': None, @@ -130,6 +132,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner modulation', 'options': dict({ }), 'original_device_class': None, @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Burner starts', 'options': dict({ }), 'original_device_class': None, @@ -233,6 +237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW gas consumption this month', 'options': dict({ }), 'original_device_class': None, @@ -284,6 +289,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW gas consumption this week', 'options': dict({ }), 'original_device_class': None, @@ -335,6 +341,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW gas consumption this year', 'options': dict({ }), 'original_device_class': None, @@ -386,6 +393,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW gas consumption today', 'options': dict({ }), 'original_device_class': None, @@ -437,6 +445,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW max temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -493,6 +502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW min temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -549,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumption this week', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -605,6 +616,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumption this year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -661,6 +673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -717,6 +730,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -773,6 +787,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating gas consumption this month', 'options': dict({ }), 'original_device_class': None, @@ -824,6 +839,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating gas consumption this week', 'options': dict({ }), 'original_device_class': None, @@ -875,6 +891,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating gas consumption this year', 'options': dict({ }), 'original_device_class': None, @@ -926,6 +943,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating gas consumption today', 'options': dict({ }), 'original_device_class': None, @@ -977,6 +995,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1033,6 +1052,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1089,6 +1109,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1145,6 +1166,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -1197,6 +1219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -1249,6 +1272,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1305,6 +1329,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Boiler supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1361,6 +1386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buffer main temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1417,6 +1443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor hours', 'options': dict({ }), 'original_device_class': None, @@ -1467,6 +1494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor phase', 'options': dict({ }), 'original_device_class': None, @@ -1517,6 +1545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor starts', 'options': dict({ }), 'original_device_class': None, @@ -1568,6 +1597,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW electricity consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1624,6 +1654,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW electricity consumption this month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1680,6 +1711,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW electricity consumption this year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1736,6 +1768,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW electricity consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1792,6 +1825,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW max temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1848,6 +1882,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW min temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1904,6 +1939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW storage temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1960,6 +1996,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2016,6 +2053,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating electricity consumption last seven days', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2072,6 +2110,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating electricity consumption this month', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2128,6 +2167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating electricity consumption this year', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2184,6 +2224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating electricity consumption today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2240,6 +2281,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating rod hours', 'options': dict({ }), 'original_device_class': None, @@ -2292,6 +2334,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heating rod starts', 'options': dict({ }), 'original_device_class': None, @@ -2343,6 +2386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2399,6 +2443,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Primary circuit supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2455,6 +2500,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2511,6 +2557,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seasonal performance factor', 'options': dict({ }), 'original_device_class': None, @@ -2562,6 +2609,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seasonal performance factor - domestic hot water', 'options': dict({ }), 'original_device_class': None, @@ -2613,6 +2661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seasonal performance factor - heating', 'options': dict({ }), 'original_device_class': None, @@ -2664,6 +2713,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Secondary circuit supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2720,6 +2770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2776,6 +2827,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2832,6 +2884,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volumetric flow', 'options': dict({ }), 'original_device_class': None, @@ -2884,6 +2937,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buffer main temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2940,6 +2994,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Buffer top temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2996,6 +3051,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor hours', 'options': dict({ }), 'original_device_class': None, @@ -3046,6 +3102,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor inlet pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3099,6 +3156,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor inlet temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3152,6 +3210,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor outlet temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3205,6 +3264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor phase', 'options': dict({ }), 'original_device_class': None, @@ -3255,6 +3315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor starts', 'options': dict({ }), 'original_device_class': None, @@ -3304,6 +3365,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Condenser subcooling temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3359,6 +3421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW max temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3415,6 +3478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW min temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3471,6 +3535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW storage temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3527,6 +3592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW storage top temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3581,6 +3647,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evaporator liquid temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3634,6 +3701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Evaporator overheat temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3689,6 +3757,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3745,6 +3814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Primary circuit return temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3801,6 +3871,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Primary circuit supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3857,6 +3928,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Return temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3913,6 +3985,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Secondary circuit supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3969,6 +4042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4025,6 +4099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation input volume flow', 'options': dict({ }), 'original_device_class': None, @@ -4083,6 +4158,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation level', 'options': dict({ }), 'original_device_class': , @@ -4141,6 +4217,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation output volume flow', 'options': dict({ }), 'original_device_class': None, @@ -4200,6 +4277,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation reason', 'options': dict({ }), 'original_device_class': , @@ -4265,6 +4343,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation level', 'options': dict({ }), 'original_device_class': , @@ -4330,6 +4409,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation reason', 'options': dict({ }), 'original_device_class': , @@ -4389,6 +4469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter hours', 'options': dict({ }), 'original_device_class': None, @@ -4441,6 +4522,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter overdue hours', 'options': dict({ }), 'original_device_class': None, @@ -4493,6 +4575,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Filter remaining hours', 'options': dict({ }), 'original_device_class': None, @@ -4545,6 +4628,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM1', 'options': dict({ }), 'original_device_class': , @@ -4598,6 +4682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': , @@ -4651,6 +4736,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': , @@ -4704,6 +4790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM4', 'options': dict({ }), 'original_device_class': , @@ -4757,6 +4844,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply fan hours', 'options': dict({ }), 'original_device_class': None, @@ -4809,6 +4897,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply fan speed', 'options': dict({ }), 'original_device_class': None, @@ -4861,6 +4950,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply humidity', 'options': dict({ }), 'original_device_class': , @@ -4914,6 +5004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Supply temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4976,6 +5067,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation level', 'options': dict({ }), 'original_device_class': , @@ -5041,6 +5133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ventilation reason', 'options': dict({ }), 'original_device_class': , @@ -5100,6 +5193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery charge total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5156,6 +5250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5209,6 +5304,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -5262,6 +5358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5318,6 +5415,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -5371,6 +5469,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5427,6 +5526,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -5480,6 +5580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': None, @@ -5532,6 +5633,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5588,6 +5690,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Valve position', 'options': dict({ }), 'original_device_class': None, @@ -5640,6 +5743,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hydraulic separator temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/vicare/snapshots/test_water_heater.ambr b/tests/components/vicare/snapshots/test_water_heater.ambr index 87d98561a86..bc1948097f6 100644 --- a/tests/components/vicare/snapshots/test_water_heater.ambr +++ b/tests/components/vicare/snapshots/test_water_heater.ambr @@ -23,6 +23,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Domestic hot water', 'options': dict({ }), 'original_device_class': None, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Domestic hot water', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/victron_ble/snapshots/test_sensor.ambr b/tests/components/victron_ble/snapshots/test_sensor.ambr index cf71d0e5ef7..f66d6a3833c 100644 --- a/tests/components/victron_ble/snapshots/test_sensor.ambr +++ b/tests/components/victron_ble/snapshots/test_sensor.ambr @@ -37,6 +37,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm', 'options': dict({ }), 'original_device_class': , @@ -104,6 +105,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -157,6 +159,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Consumed ampere hours', 'options': dict({ }), 'original_device_class': None, @@ -209,6 +212,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -265,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Midpoint voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -321,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Remaining minutes', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -377,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -430,6 +437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -486,6 +494,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -542,6 +551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -613,6 +623,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Alarm', 'options': dict({ }), 'original_device_class': , @@ -680,6 +691,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -754,6 +766,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Meter type', 'options': dict({ }), 'original_device_class': , @@ -824,6 +837,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -877,6 +891,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -933,6 +948,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -989,6 +1005,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1045,6 +1062,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1101,6 +1119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1157,6 +1176,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'External device load', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1213,6 +1233,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -1266,6 +1287,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Solar power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1322,6 +1344,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Yield today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1378,6 +1401,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC-in power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1438,6 +1462,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC-in state', 'options': dict({ }), 'original_device_class': , @@ -1494,6 +1519,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'AC-out power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1550,6 +1576,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -1603,6 +1630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1659,6 +1687,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1715,6 +1744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery voltage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1789,6 +1819,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Device state', 'options': dict({ }), 'original_device_class': , @@ -1859,6 +1890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/victron_remote_monitoring/snapshots/test_sensor.ambr b/tests/components/victron_remote_monitoring/snapshots/test_sensor.ambr index 422ab254f52..8087a570a71 100644 --- a/tests/components/victron_remote_monitoring/snapshots/test_sensor.ambr +++ b/tests/components/victron_remote_monitoring/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy consumption - Current hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -81,6 +82,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy consumption - Next hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -140,6 +142,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy consumption - Today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy consumption - Today remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy consumption - Tomorrow', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -317,6 +322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy consumption - Yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -376,6 +382,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy production - Current hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -435,6 +442,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy production - Next hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -494,6 +502,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy production - Today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -553,6 +562,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy production - Today remaining', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -612,6 +622,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy production - Tomorrow', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -671,6 +682,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated energy production - Yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -728,6 +740,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest consumption peak time - Today', 'options': dict({ }), 'original_device_class': , @@ -777,6 +790,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest consumption peak time - Tomorrow', 'options': dict({ }), 'original_device_class': , @@ -826,6 +840,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest consumption peak time - Yesterday', 'options': dict({ }), 'original_device_class': , @@ -875,6 +890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest peak time - Today', 'options': dict({ }), 'original_device_class': , @@ -924,6 +940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest peak time - Tomorrow', 'options': dict({ }), 'original_device_class': , @@ -973,6 +990,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Highest peak time - Yesterday', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vivotek/snapshots/test_camera.ambr b/tests/components/vivotek/snapshots/test_camera.ambr index 644ab34bc02..46b66fa93f0 100644 --- a/tests/components/vivotek/snapshots/test_camera.ambr +++ b/tests/components/vivotek/snapshots/test_camera.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vivotek Camera', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vodafone_station/conftest.py b/tests/components/vodafone_station/conftest.py index a3ffdf9f14e..7dca0181c9c 100644 --- a/tests/components/vodafone_station/conftest.py +++ b/tests/components/vodafone_station/conftest.py @@ -3,6 +3,7 @@ from datetime import UTC, datetime from aiovodafone.api import VodafoneStationDevice +from aiovodafone.const import WIFI_DATA import pytest from yarl import URL @@ -23,6 +24,7 @@ from .const import ( TEST_TYPE, TEST_URL, TEST_USERNAME, + TEST_WIFI_DATA, ) from tests.common import ( @@ -93,12 +95,14 @@ def mock_vodafone_station_router() -> Generator[AsyncMock]: router.get_sensor_data = AsyncMock( return_value=load_json_object_fixture("get_sensor_data.json", DOMAIN) ) + router.get_wifi_data = AsyncMock(return_value={WIFI_DATA: TEST_WIFI_DATA}) router.convert_uptime.return_value = datetime( 2024, 11, 19, 20, 19, 0, tzinfo=UTC ) router.base_url = URL(TEST_URL) router.restart_connection = AsyncMock(return_value=True) router.restart_router = AsyncMock(return_value=True) + router.set_wifi_status = AsyncMock(return_value=True) yield router @@ -120,3 +124,13 @@ def mock_config_entry() -> MockConfigEntry: version=1, minor_version=2, ) + + +@pytest.fixture(autouse=True) +def mock_getrandbits(): + """Mock image access token which normally is randomized.""" + with patch( + "homeassistant.components.image.SystemRandom.getrandbits", + return_value=1, + ): + yield diff --git a/tests/components/vodafone_station/const.py b/tests/components/vodafone_station/const.py index 435bad01874..7f640ab442f 100644 --- a/tests/components/vodafone_station/const.py +++ b/tests/components/vodafone_station/const.py @@ -1,5 +1,7 @@ """Common stuff for Vodafone Station tests.""" +from io import BytesIO + from aiovodafone.models import DeviceType DEVICE_1_HOST = "WifiDevice0" @@ -13,3 +15,16 @@ TEST_TYPE = DeviceType.SERCOMM TEST_URL = f"https://{TEST_HOST}" TEST_USERNAME = "fake_username" TEST_SERIAL_NUMBER = "m123456789" + +TEST_WIFI_DATA: dict = { + "guest": { + "on": 1, + "ssid": "Wifi-Guest", + "qr_code": BytesIO(b"fake-qr-code-guest"), + }, + "guest_5g": { + "on": 0, + "ssid": "Wifi-Guest-5Ghz", + "qr_code": BytesIO(b"fake-qr-code-guest-5ghz"), + }, +} diff --git a/tests/components/vodafone_station/snapshots/test_button.ambr b/tests/components/vodafone_station/snapshots/test_button.ambr index f644da96c09..2c83c75ac12 100644 --- a/tests/components/vodafone_station/snapshots/test_button.ambr +++ b/tests/components/vodafone_station/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vodafone_station/snapshots/test_device_tracker.ambr b/tests/components/vodafone_station/snapshots/test_device_tracker.ambr index f4f88c17aa6..f6d9329c787 100644 --- a/tests/components/vodafone_station/snapshots/test_device_tracker.ambr +++ b/tests/components/vodafone_station/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LanDevice1', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'WifiDevice0', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/vodafone_station/snapshots/test_image.ambr b/tests/components/vodafone_station/snapshots/test_image.ambr new file mode 100644 index 00000000000..07ff84dc325 --- /dev/null +++ b/tests/components/vodafone_station/snapshots/test_image.ambr @@ -0,0 +1,106 @@ +# serializer version: 1 +# name: test_all_entities[image.vodafone_station_m123456789_guest_5ghz_network-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': , + 'entity_id': 'image.vodafone_station_m123456789_guest_5ghz_network', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Guest 5GHz network', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Guest 5GHz network', + 'platform': 'vodafone_station', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'guest_5g', + 'unique_id': 'm123456789-guest_5g-qr-code', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[image.vodafone_station_m123456789_guest_5ghz_network-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'access_token': '1', + 'entity_picture': '/api/image_proxy/image.vodafone_station_m123456789_guest_5ghz_network?token=1', + 'friendly_name': 'Vodafone Station (m123456789) Guest 5GHz network', + }), + 'context': , + 'entity_id': 'image.vodafone_station_m123456789_guest_5ghz_network', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_all_entities[image.vodafone_station_m123456789_guest_network-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': , + 'entity_id': 'image.vodafone_station_m123456789_guest_network', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Guest network', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Guest network', + 'platform': 'vodafone_station', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'guest', + 'unique_id': 'm123456789-guest-qr-code', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[image.vodafone_station_m123456789_guest_network-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'access_token': '1', + 'entity_picture': '/api/image_proxy/image.vodafone_station_m123456789_guest_network?token=1', + 'friendly_name': 'Vodafone Station (m123456789) Guest network', + }), + 'context': , + 'entity_id': 'image.vodafone_station_m123456789_guest_network', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- +# name: test_image_entity + b'fake-qr-code-guest' +# --- diff --git a/tests/components/vodafone_station/snapshots/test_sensor.ambr b/tests/components/vodafone_station/snapshots/test_sensor.ambr index d046f1f1f0e..215de779dd0 100644 --- a/tests/components/vodafone_station/snapshots/test_sensor.ambr +++ b/tests/components/vodafone_station/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active connection', 'options': dict({ }), 'original_device_class': , @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'CPU usage', 'options': dict({ }), 'original_device_class': None, @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory usage', 'options': dict({ }), 'original_device_class': None, @@ -178,6 +181,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reboot cause', 'options': dict({ }), 'original_device_class': None, @@ -226,6 +230,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/vodafone_station/test_image.py b/tests/components/vodafone_station/test_image.py new file mode 100644 index 00000000000..4fc7b2a60cf --- /dev/null +++ b/tests/components/vodafone_station/test_image.py @@ -0,0 +1,148 @@ +"""Tests for Vodafone Station image platform.""" + +from http import HTTPStatus +from io import BytesIO +from unittest.mock import AsyncMock, patch + +from aiovodafone.const import WIFI_DATA +from freezegun.api import FrozenDateTimeFactory +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.image import DOMAIN as IMAGE_DOMAIN +from homeassistant.components.vodafone_station.const import SCAN_INTERVAL +from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import setup_integration +from .const import TEST_SERIAL_NUMBER + +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform +from tests.typing import ClientSessionGenerator + + +@pytest.mark.freeze_time("2026-01-05T15:00:00+00:00") +async def test_all_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + mock_vodafone_station_router: AsyncMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test all entities.""" + + with patch("homeassistant.components.vodafone_station.PLATFORMS", [Platform.IMAGE]): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +async def test_image_entity( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, + mock_vodafone_station_router: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test image entity.""" + + entity_id = f"image.vodafone_station_{TEST_SERIAL_NUMBER}_guest_network" + + await setup_integration(hass, mock_config_entry) + + assert mock_config_entry.state is ConfigEntryState.LOADED + + # test image entities are generated as expected + states = hass.states.async_all(IMAGE_DOMAIN) + assert len(states) == 2 + + state = states[0] + assert state.name == f"Vodafone Station ({TEST_SERIAL_NUMBER}) Guest network" + assert state.entity_id == entity_id + + access_token = state.attributes["access_token"] + assert state.attributes == { + "access_token": access_token, + "entity_picture": f"/api/image_proxy/{entity_id}?token={access_token}", + "friendly_name": f"Vodafone Station ({TEST_SERIAL_NUMBER}) Guest network", + } + + entity_entry = entity_registry.async_get(entity_id) + assert entity_entry is not None + assert entity_entry.unique_id == f"{TEST_SERIAL_NUMBER}-guest-qr-code" + + # test image download + client = await hass_client() + resp = await client.get(f"/api/image_proxy/{entity_id}") + assert resp.status == HTTPStatus.OK + + body = await resp.read() + assert body == snapshot + + +async def test_image_update( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + freezer: FrozenDateTimeFactory, + mock_vodafone_station_router: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test image update.""" + + entity_id = f"image.vodafone_station_{TEST_SERIAL_NUMBER}_guest_network" + + await setup_integration(hass, mock_config_entry) + + assert mock_config_entry.state is ConfigEntryState.LOADED + + client = await hass_client() + resp = await client.get(f"/api/image_proxy/{entity_id}") + assert resp.status == HTTPStatus.OK + + resp_body = await resp.read() + + mock_vodafone_station_router.get_wifi_data.return_value = { + WIFI_DATA: { + "guest": { + "on": 1, + "ssid": "Wifi-Guest", + "qr_code": BytesIO(b"fake-qr-code-guest-updated"), + }, + "guest_5g": { + "on": 0, + "ssid": "Wifi-Guest-5Ghz", + "qr_code": BytesIO(b"fake-qr-code-guest-5ghz-updated"), + }, + } + } + + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + resp = await client.get(f"/api/image_proxy/{entity_id}") + assert resp.status == HTTPStatus.OK + + resp_body_new = await resp.read() + assert resp_body != resp_body_new + + +async def test_no_wifi_data( + hass: HomeAssistant, + mock_vodafone_station_router: AsyncMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test image entity.""" + + mock_vodafone_station_router.get_wifi_data.return_value = {WIFI_DATA: {}} + + await setup_integration(hass, mock_config_entry) + + assert mock_config_entry.state is ConfigEntryState.LOADED + + # test image entities are not generated + states = hass.states.async_all(IMAGE_DOMAIN) + assert len(states) == 0 diff --git a/tests/components/volvo/snapshots/test_binary_sensor.ambr b/tests/components/volvo/snapshots/test_binary_sensor.ambr index 40922692108..84865d55a9f 100644 --- a/tests/components/volvo/snapshots/test_binary_sensor.ambr +++ b/tests/components/volvo/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake fluid', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light center', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light left', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light right', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Coolant level', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light left', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light right', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front left', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front right', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear left', 'options': dict({ }), 'original_device_class': , @@ -510,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear right', 'options': dict({ }), 'original_device_class': , @@ -559,6 +570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine status', 'options': dict({ }), 'original_device_class': , @@ -608,6 +620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light front', 'options': dict({ }), 'original_device_class': , @@ -657,6 +670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light rear', 'options': dict({ }), 'original_device_class': , @@ -706,6 +720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hazard lights', 'options': dict({ }), 'original_device_class': , @@ -755,6 +770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam left', 'options': dict({ }), 'original_device_class': , @@ -804,6 +820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam right', 'options': dict({ }), 'original_device_class': , @@ -853,6 +870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hood', 'options': dict({ }), 'original_device_class': , @@ -902,6 +920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam left', 'options': dict({ }), 'original_device_class': , @@ -951,6 +970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam right', 'options': dict({ }), 'original_device_class': , @@ -1000,6 +1020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil level', 'options': dict({ }), 'original_device_class': , @@ -1049,6 +1070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front left', 'options': dict({ }), 'original_device_class': , @@ -1098,6 +1120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front right', 'options': dict({ }), 'original_device_class': , @@ -1147,6 +1170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear left', 'options': dict({ }), 'original_device_class': , @@ -1196,6 +1220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear right', 'options': dict({ }), 'original_device_class': , @@ -1245,6 +1270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Registration plate light', 'options': dict({ }), 'original_device_class': , @@ -1294,6 +1320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse lights', 'options': dict({ }), 'original_device_class': , @@ -1343,6 +1370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side mark lights', 'options': dict({ }), 'original_device_class': , @@ -1392,6 +1420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -1441,6 +1470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tailgate', 'options': dict({ }), 'original_device_class': , @@ -1490,6 +1520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank lid', 'options': dict({ }), 'original_device_class': , @@ -1539,6 +1570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front left', 'options': dict({ }), 'original_device_class': , @@ -1588,6 +1620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front right', 'options': dict({ }), 'original_device_class': , @@ -1637,6 +1670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear left', 'options': dict({ }), 'original_device_class': , @@ -1686,6 +1720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear right', 'options': dict({ }), 'original_device_class': , @@ -1735,6 +1770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front left', 'options': dict({ }), 'original_device_class': , @@ -1784,6 +1820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front right', 'options': dict({ }), 'original_device_class': , @@ -1833,6 +1870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear left', 'options': dict({ }), 'original_device_class': , @@ -1882,6 +1920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear right', 'options': dict({ }), 'original_device_class': , @@ -1931,6 +1970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Washer fluid', 'options': dict({ }), 'original_device_class': , @@ -1980,6 +2020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front left', 'options': dict({ }), 'original_device_class': , @@ -2029,6 +2070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front right', 'options': dict({ }), 'original_device_class': , @@ -2078,6 +2120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear left', 'options': dict({ }), 'original_device_class': , @@ -2127,6 +2170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear right', 'options': dict({ }), 'original_device_class': , @@ -2176,6 +2220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake fluid', 'options': dict({ }), 'original_device_class': , @@ -2225,6 +2270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light center', 'options': dict({ }), 'original_device_class': , @@ -2274,6 +2320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light left', 'options': dict({ }), 'original_device_class': , @@ -2323,6 +2370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light right', 'options': dict({ }), 'original_device_class': , @@ -2372,6 +2420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Coolant level', 'options': dict({ }), 'original_device_class': , @@ -2421,6 +2470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light left', 'options': dict({ }), 'original_device_class': , @@ -2470,6 +2520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light right', 'options': dict({ }), 'original_device_class': , @@ -2519,6 +2570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front left', 'options': dict({ }), 'original_device_class': , @@ -2568,6 +2620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front right', 'options': dict({ }), 'original_device_class': , @@ -2617,6 +2670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear left', 'options': dict({ }), 'original_device_class': , @@ -2666,6 +2720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear right', 'options': dict({ }), 'original_device_class': , @@ -2715,6 +2770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine status', 'options': dict({ }), 'original_device_class': , @@ -2764,6 +2820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light front', 'options': dict({ }), 'original_device_class': , @@ -2813,6 +2870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light rear', 'options': dict({ }), 'original_device_class': , @@ -2862,6 +2920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hazard lights', 'options': dict({ }), 'original_device_class': , @@ -2911,6 +2970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam left', 'options': dict({ }), 'original_device_class': , @@ -2960,6 +3020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam right', 'options': dict({ }), 'original_device_class': , @@ -3009,6 +3070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hood', 'options': dict({ }), 'original_device_class': , @@ -3058,6 +3120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam left', 'options': dict({ }), 'original_device_class': , @@ -3107,6 +3170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam right', 'options': dict({ }), 'original_device_class': , @@ -3156,6 +3220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil level', 'options': dict({ }), 'original_device_class': , @@ -3205,6 +3270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front left', 'options': dict({ }), 'original_device_class': , @@ -3254,6 +3320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front right', 'options': dict({ }), 'original_device_class': , @@ -3303,6 +3370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear left', 'options': dict({ }), 'original_device_class': , @@ -3352,6 +3420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear right', 'options': dict({ }), 'original_device_class': , @@ -3401,6 +3470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Registration plate light', 'options': dict({ }), 'original_device_class': , @@ -3450,6 +3520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse lights', 'options': dict({ }), 'original_device_class': , @@ -3499,6 +3570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side mark lights', 'options': dict({ }), 'original_device_class': , @@ -3548,6 +3620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -3597,6 +3670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tailgate', 'options': dict({ }), 'original_device_class': , @@ -3646,6 +3720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank lid', 'options': dict({ }), 'original_device_class': , @@ -3695,6 +3770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front left', 'options': dict({ }), 'original_device_class': , @@ -3744,6 +3820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front right', 'options': dict({ }), 'original_device_class': , @@ -3793,6 +3870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear left', 'options': dict({ }), 'original_device_class': , @@ -3842,6 +3920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear right', 'options': dict({ }), 'original_device_class': , @@ -3891,6 +3970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front left', 'options': dict({ }), 'original_device_class': , @@ -3940,6 +4020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front right', 'options': dict({ }), 'original_device_class': , @@ -3989,6 +4070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear left', 'options': dict({ }), 'original_device_class': , @@ -4038,6 +4120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear right', 'options': dict({ }), 'original_device_class': , @@ -4087,6 +4170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Washer fluid', 'options': dict({ }), 'original_device_class': , @@ -4136,6 +4220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front left', 'options': dict({ }), 'original_device_class': , @@ -4185,6 +4270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front right', 'options': dict({ }), 'original_device_class': , @@ -4234,6 +4320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear left', 'options': dict({ }), 'original_device_class': , @@ -4283,6 +4370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear right', 'options': dict({ }), 'original_device_class': , @@ -4332,6 +4420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake fluid', 'options': dict({ }), 'original_device_class': , @@ -4381,6 +4470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light center', 'options': dict({ }), 'original_device_class': , @@ -4430,6 +4520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light left', 'options': dict({ }), 'original_device_class': , @@ -4479,6 +4570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light right', 'options': dict({ }), 'original_device_class': , @@ -4528,6 +4620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Coolant level', 'options': dict({ }), 'original_device_class': , @@ -4577,6 +4670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light left', 'options': dict({ }), 'original_device_class': , @@ -4626,6 +4720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light right', 'options': dict({ }), 'original_device_class': , @@ -4675,6 +4770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front left', 'options': dict({ }), 'original_device_class': , @@ -4724,6 +4820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front right', 'options': dict({ }), 'original_device_class': , @@ -4773,6 +4870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear left', 'options': dict({ }), 'original_device_class': , @@ -4822,6 +4920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear right', 'options': dict({ }), 'original_device_class': , @@ -4871,6 +4970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine status', 'options': dict({ }), 'original_device_class': , @@ -4920,6 +5020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light front', 'options': dict({ }), 'original_device_class': , @@ -4969,6 +5070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light rear', 'options': dict({ }), 'original_device_class': , @@ -5018,6 +5120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hazard lights', 'options': dict({ }), 'original_device_class': , @@ -5067,6 +5170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam left', 'options': dict({ }), 'original_device_class': , @@ -5116,6 +5220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam right', 'options': dict({ }), 'original_device_class': , @@ -5165,6 +5270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hood', 'options': dict({ }), 'original_device_class': , @@ -5214,6 +5320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam left', 'options': dict({ }), 'original_device_class': , @@ -5263,6 +5370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam right', 'options': dict({ }), 'original_device_class': , @@ -5312,6 +5420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil level', 'options': dict({ }), 'original_device_class': , @@ -5361,6 +5470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front left', 'options': dict({ }), 'original_device_class': , @@ -5410,6 +5520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front right', 'options': dict({ }), 'original_device_class': , @@ -5459,6 +5570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear left', 'options': dict({ }), 'original_device_class': , @@ -5508,6 +5620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear right', 'options': dict({ }), 'original_device_class': , @@ -5557,6 +5670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Registration plate light', 'options': dict({ }), 'original_device_class': , @@ -5606,6 +5720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse lights', 'options': dict({ }), 'original_device_class': , @@ -5655,6 +5770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side mark lights', 'options': dict({ }), 'original_device_class': , @@ -5704,6 +5820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -5753,6 +5870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tailgate', 'options': dict({ }), 'original_device_class': , @@ -5802,6 +5920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank lid', 'options': dict({ }), 'original_device_class': , @@ -5851,6 +5970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front left', 'options': dict({ }), 'original_device_class': , @@ -5900,6 +6020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front right', 'options': dict({ }), 'original_device_class': , @@ -5949,6 +6070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear left', 'options': dict({ }), 'original_device_class': , @@ -5998,6 +6120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear right', 'options': dict({ }), 'original_device_class': , @@ -6047,6 +6170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front left', 'options': dict({ }), 'original_device_class': , @@ -6096,6 +6220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front right', 'options': dict({ }), 'original_device_class': , @@ -6145,6 +6270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear left', 'options': dict({ }), 'original_device_class': , @@ -6194,6 +6320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear right', 'options': dict({ }), 'original_device_class': , @@ -6243,6 +6370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Washer fluid', 'options': dict({ }), 'original_device_class': , @@ -6292,6 +6420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front left', 'options': dict({ }), 'original_device_class': , @@ -6341,6 +6470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front right', 'options': dict({ }), 'original_device_class': , @@ -6390,6 +6520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear left', 'options': dict({ }), 'original_device_class': , @@ -6439,6 +6570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear right', 'options': dict({ }), 'original_device_class': , @@ -6488,6 +6620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake fluid', 'options': dict({ }), 'original_device_class': , @@ -6537,6 +6670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light center', 'options': dict({ }), 'original_device_class': , @@ -6586,6 +6720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light left', 'options': dict({ }), 'original_device_class': , @@ -6635,6 +6770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Brake light right', 'options': dict({ }), 'original_device_class': , @@ -6684,6 +6820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Coolant level', 'options': dict({ }), 'original_device_class': , @@ -6733,6 +6870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light left', 'options': dict({ }), 'original_device_class': , @@ -6782,6 +6920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Daytime running light right', 'options': dict({ }), 'original_device_class': , @@ -6831,6 +6970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front left', 'options': dict({ }), 'original_device_class': , @@ -6880,6 +7020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door front right', 'options': dict({ }), 'original_device_class': , @@ -6929,6 +7070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear left', 'options': dict({ }), 'original_device_class': , @@ -6978,6 +7120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door rear right', 'options': dict({ }), 'original_device_class': , @@ -7027,6 +7170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Engine status', 'options': dict({ }), 'original_device_class': , @@ -7076,6 +7220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light front', 'options': dict({ }), 'original_device_class': , @@ -7125,6 +7270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fog light rear', 'options': dict({ }), 'original_device_class': , @@ -7174,6 +7320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hazard lights', 'options': dict({ }), 'original_device_class': , @@ -7223,6 +7370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam left', 'options': dict({ }), 'original_device_class': , @@ -7272,6 +7420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'High beam right', 'options': dict({ }), 'original_device_class': , @@ -7321,6 +7470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hood', 'options': dict({ }), 'original_device_class': , @@ -7370,6 +7520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam left', 'options': dict({ }), 'original_device_class': , @@ -7419,6 +7570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Low beam right', 'options': dict({ }), 'original_device_class': , @@ -7468,6 +7620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Oil level', 'options': dict({ }), 'original_device_class': , @@ -7517,6 +7670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front left', 'options': dict({ }), 'original_device_class': , @@ -7566,6 +7720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light front right', 'options': dict({ }), 'original_device_class': , @@ -7615,6 +7770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear left', 'options': dict({ }), 'original_device_class': , @@ -7664,6 +7820,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Position light rear right', 'options': dict({ }), 'original_device_class': , @@ -7713,6 +7870,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Registration plate light', 'options': dict({ }), 'original_device_class': , @@ -7762,6 +7920,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse lights', 'options': dict({ }), 'original_device_class': , @@ -7811,6 +7970,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Side mark lights', 'options': dict({ }), 'original_device_class': , @@ -7860,6 +8020,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sunroof', 'options': dict({ }), 'original_device_class': , @@ -7909,6 +8070,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tailgate', 'options': dict({ }), 'original_device_class': , @@ -7958,6 +8120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tank lid', 'options': dict({ }), 'original_device_class': , @@ -8007,6 +8170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front left', 'options': dict({ }), 'original_device_class': , @@ -8056,6 +8220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire front right', 'options': dict({ }), 'original_device_class': , @@ -8105,6 +8270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear left', 'options': dict({ }), 'original_device_class': , @@ -8154,6 +8320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tire rear right', 'options': dict({ }), 'original_device_class': , @@ -8203,6 +8370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front left', 'options': dict({ }), 'original_device_class': , @@ -8252,6 +8420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication front right', 'options': dict({ }), 'original_device_class': , @@ -8301,6 +8470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear left', 'options': dict({ }), 'original_device_class': , @@ -8350,6 +8520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Turn indication rear right', 'options': dict({ }), 'original_device_class': , @@ -8399,6 +8570,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Washer fluid', 'options': dict({ }), 'original_device_class': , @@ -8448,6 +8620,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front left', 'options': dict({ }), 'original_device_class': , @@ -8497,6 +8670,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window front right', 'options': dict({ }), 'original_device_class': , @@ -8546,6 +8720,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear left', 'options': dict({ }), 'original_device_class': , @@ -8595,6 +8770,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Window rear right', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/volvo/snapshots/test_button.ambr b/tests/components/volvo/snapshots/test_button.ambr index 1b4a12247cd..3597b9b9447 100644 --- a/tests/components/volvo/snapshots/test_button.ambr +++ b/tests/components/volvo/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk & flash', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock reduced guard', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start climatization', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop climatization', 'options': dict({ }), 'original_device_class': None, @@ -308,6 +314,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash', 'options': dict({ }), 'original_device_class': None, @@ -356,6 +363,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk & flash', 'options': dict({ }), 'original_device_class': None, @@ -452,6 +461,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock reduced guard', 'options': dict({ }), 'original_device_class': None, @@ -500,6 +510,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start climatization', 'options': dict({ }), 'original_device_class': None, @@ -548,6 +559,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop climatization', 'options': dict({ }), 'original_device_class': None, @@ -596,6 +608,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash', 'options': dict({ }), 'original_device_class': None, @@ -644,6 +657,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk', 'options': dict({ }), 'original_device_class': None, @@ -692,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk & flash', 'options': dict({ }), 'original_device_class': None, @@ -740,6 +755,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock reduced guard', 'options': dict({ }), 'original_device_class': None, @@ -788,6 +804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start climatization', 'options': dict({ }), 'original_device_class': None, @@ -836,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop climatization', 'options': dict({ }), 'original_device_class': None, @@ -884,6 +902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flash', 'options': dict({ }), 'original_device_class': None, @@ -932,6 +951,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk', 'options': dict({ }), 'original_device_class': None, @@ -980,6 +1000,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Honk & flash', 'options': dict({ }), 'original_device_class': None, @@ -1028,6 +1049,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock reduced guard', 'options': dict({ }), 'original_device_class': None, @@ -1076,6 +1098,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start climatization', 'options': dict({ }), 'original_device_class': None, @@ -1124,6 +1147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Start engine', 'options': dict({ }), 'original_device_class': None, @@ -1172,6 +1196,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop climatization', 'options': dict({ }), 'original_device_class': None, @@ -1220,6 +1245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Stop engine', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/volvo/snapshots/test_device_tracker.ambr b/tests/components/volvo/snapshots/test_device_tracker.ambr index 92bdfa517eb..9033097ba0f 100644 --- a/tests/components/volvo/snapshots/test_device_tracker.ambr +++ b/tests/components/volvo/snapshots/test_device_tracker.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -72,6 +73,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, @@ -176,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Location', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/volvo/snapshots/test_lock.ambr b/tests/components/volvo/snapshots/test_lock.ambr index c1cde82920f..3e9962d1315 100644 --- a/tests/components/volvo/snapshots/test_lock.ambr +++ b/tests/components/volvo/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/volvo/snapshots/test_sensor.ambr b/tests/components/volvo/snapshots/test_sensor.ambr index 1e2441f7c07..d6f893ec1dc 100644 --- a/tests/components/volvo/snapshots/test_sensor.ambr +++ b/tests/components/volvo/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -137,6 +139,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car connection', 'options': dict({ }), 'original_device_class': , @@ -199,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging connection status', 'options': dict({ }), 'original_device_class': , @@ -255,6 +259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -316,6 +321,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power status', 'options': dict({ }), 'original_device_class': , @@ -380,6 +386,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -443,6 +450,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging type', 'options': dict({ }), 'original_device_class': , @@ -497,6 +505,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -551,6 +560,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -607,6 +617,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -663,6 +674,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -719,6 +731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -787,6 +800,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service', 'options': dict({ }), 'original_device_class': , @@ -849,6 +863,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target battery charge level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -903,6 +918,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to engine service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -959,6 +975,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1015,6 +1032,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1071,6 +1089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1127,6 +1146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1182,6 +1202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1238,6 +1259,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1294,6 +1316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1356,6 +1379,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car connection', 'options': dict({ }), 'original_device_class': , @@ -1412,6 +1436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1466,6 +1491,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty tank', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1522,6 +1548,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1578,6 +1605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel amount', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1634,6 +1662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1702,6 +1731,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service', 'options': dict({ }), 'original_device_class': , @@ -1766,6 +1796,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to engine service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1822,6 +1853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1878,6 +1910,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1934,6 +1967,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1990,6 +2024,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average fuel consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2045,6 +2080,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2101,6 +2137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2157,6 +2194,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2211,6 +2249,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2272,6 +2311,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car connection', 'options': dict({ }), 'original_device_class': , @@ -2334,6 +2374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging connection status', 'options': dict({ }), 'original_device_class': , @@ -2390,6 +2431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging limit', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2446,6 +2488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2507,6 +2550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power status', 'options': dict({ }), 'original_device_class': , @@ -2571,6 +2615,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -2634,6 +2679,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging type', 'options': dict({ }), 'original_device_class': , @@ -2688,6 +2734,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2742,6 +2789,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2798,6 +2846,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -2854,6 +2903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2910,6 +2960,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -2978,6 +3029,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service', 'options': dict({ }), 'original_device_class': , @@ -3040,6 +3092,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target battery charge level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3094,6 +3147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to engine service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3150,6 +3204,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3206,6 +3261,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3262,6 +3318,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3318,6 +3375,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3373,6 +3431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3429,6 +3488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3485,6 +3545,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3539,6 +3600,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3600,6 +3662,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car connection', 'options': dict({ }), 'original_device_class': , @@ -3662,6 +3725,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging connection status', 'options': dict({ }), 'original_device_class': , @@ -3725,6 +3789,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -3782,6 +3847,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3836,6 +3902,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3892,6 +3959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty tank', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -3948,6 +4016,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4004,6 +4073,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel amount', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4060,6 +4130,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4128,6 +4199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service', 'options': dict({ }), 'original_device_class': , @@ -4190,6 +4262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target battery charge level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4244,6 +4317,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to engine service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4300,6 +4374,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4356,6 +4431,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4412,6 +4488,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average fuel consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4467,6 +4544,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4523,6 +4601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4579,6 +4658,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4641,6 +4721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car connection', 'options': dict({ }), 'original_device_class': , @@ -4697,6 +4778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4751,6 +4833,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty tank', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4807,6 +4890,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -4863,6 +4947,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel amount', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4919,6 +5004,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -4987,6 +5073,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service', 'options': dict({ }), 'original_device_class': , @@ -5051,6 +5138,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to engine service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5107,6 +5195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5163,6 +5252,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5219,6 +5309,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5275,6 +5366,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average fuel consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -5330,6 +5422,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5386,6 +5479,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5442,6 +5536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5496,6 +5591,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery capacity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -5557,6 +5653,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Car connection', 'options': dict({ }), 'original_device_class': , @@ -5619,6 +5716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging connection status', 'options': dict({ }), 'original_device_class': , @@ -5680,6 +5778,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging power status', 'options': dict({ }), 'original_device_class': , @@ -5744,6 +5843,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging status', 'options': dict({ }), 'original_device_class': , @@ -5807,6 +5907,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Charging type', 'options': dict({ }), 'original_device_class': , @@ -5861,6 +5962,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Direction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5915,6 +6017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty battery', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -5971,6 +6074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to empty tank', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6027,6 +6131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6083,6 +6188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated charging time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6139,6 +6245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fuel amount', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6195,6 +6302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Odometer', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6263,6 +6371,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Service', 'options': dict({ }), 'original_device_class': , @@ -6325,6 +6434,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target battery charge level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6379,6 +6489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to engine service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6435,6 +6546,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to service', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -6491,6 +6603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic average fuel consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6546,6 +6659,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6602,6 +6716,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip automatic distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6658,6 +6773,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average energy consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6713,6 +6829,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average fuel consumption', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -6768,6 +6885,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual average speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -6824,6 +6942,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Trip manual distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/waqi/snapshots/test_sensor.ambr b/tests/components/waqi/snapshots/test_sensor.ambr index d0c46346b2e..3e87d83d411 100644 --- a/tests/components/waqi/snapshots/test_sensor.ambr +++ b/tests/components/waqi/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air quality index', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Carbon monoxide', 'options': dict({ }), 'original_device_class': None, @@ -135,6 +137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dominant pollutant', 'options': dict({ }), 'original_device_class': , @@ -196,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Humidity', 'options': dict({ }), 'original_device_class': , @@ -250,6 +254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nitrogen dioxide', 'options': dict({ }), 'original_device_class': None, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Ozone', 'options': dict({ }), 'original_device_class': None, @@ -354,6 +360,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM10', 'options': dict({ }), 'original_device_class': None, @@ -406,6 +413,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'PM2.5', 'options': dict({ }), 'original_device_class': None, @@ -458,6 +466,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -515,6 +524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sulphur dioxide', 'options': dict({ }), 'original_device_class': None, @@ -567,6 +577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -624,6 +635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Visibility using nephelometry', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/water_heater/test_device_action.py b/tests/components/water_heater/test_device_action.py index 943aa3373a0..82179c63237 100644 --- a/tests/components/water_heater/test_device_action.py +++ b/tests/components/water_heater/test_device_action.py @@ -19,11 +19,6 @@ from tests.common import ( ) -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - async def test_get_actions( hass: HomeAssistant, device_registry: dr.DeviceRegistry, diff --git a/tests/components/watergate/snapshots/test_event.ambr b/tests/components/watergate/snapshots/test_event.ambr index a7a019cc83b..6aae60cc1ae 100644 --- a/tests/components/watergate/snapshots/test_event.ambr +++ b/tests/components/watergate/snapshots/test_event.ambr @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Duration auto shut-off', 'options': dict({ }), 'original_device_class': None, @@ -80,6 +81,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume auto shut-off', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/watergate/snapshots/test_sensor.ambr b/tests/components/watergate/snapshots/test_sensor.ambr index 9ba7bbd3024..d12a5a82935 100644 --- a/tests/components/watergate/snapshots/test_sensor.ambr +++ b/tests/components/watergate/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'MQTT up since', 'options': dict({ }), 'original_device_class': , @@ -75,6 +76,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power supply mode', 'options': dict({ }), 'original_device_class': , @@ -131,6 +133,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Signal strength', 'options': dict({ }), 'original_device_class': , @@ -182,6 +185,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Up since', 'options': dict({ }), 'original_device_class': , @@ -233,6 +237,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume flow rate', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -289,6 +294,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water meter duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -345,6 +351,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water meter volume', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -401,6 +408,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -457,6 +465,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -511,6 +520,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi up since', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/watts/snapshots/test_climate.ambr b/tests/components/watts/snapshots/test_climate.ambr index 88417d17cbb..d6d0d04c477 100644 --- a/tests/components/watts/snapshots/test_climate.ambr +++ b/tests/components/watts/snapshots/test_climate.ambr @@ -28,6 +28,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -94,6 +95,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/weatherflow_cloud/snapshots/test_sensor.ambr b/tests/components/weatherflow_cloud/snapshots/test_sensor.ambr index cd6280077a2..e446b403cfc 100644 --- a/tests/components/weatherflow_cloud/snapshots/test_sensor.ambr +++ b/tests/components/weatherflow_cloud/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Air density', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 5, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Dew point', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -135,6 +137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Feels like', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -192,6 +195,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heat index', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -249,6 +253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lightning count', 'options': dict({ }), 'original_device_class': None, @@ -301,6 +306,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lightning count last 1 hr', 'options': dict({ }), 'original_device_class': None, @@ -353,6 +359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lightning count last 3 hr', 'options': dict({ }), 'original_device_class': None, @@ -405,6 +412,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lightning last distance', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -460,6 +468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lightning last strike', 'options': dict({ }), 'original_device_class': , @@ -512,6 +521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nearcast precipitation duration yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -568,6 +578,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nearcast precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -624,6 +635,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nearcast precipitation yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -680,6 +692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation duration today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -736,6 +749,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation duration yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -792,6 +806,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -854,6 +869,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation type yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -916,6 +932,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Precipitation yesterday', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -972,6 +989,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure barometric', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1032,6 +1050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure sea level', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 3, @@ -1092,6 +1111,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain last hour', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1148,6 +1168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1205,6 +1226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wet bulb globe temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1262,6 +1284,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wet bulb temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1319,6 +1342,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind chill', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1374,6 +1398,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind direction', 'options': dict({ }), 'original_device_class': , @@ -1427,6 +1452,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind gust', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1487,6 +1513,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind lull', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1547,6 +1574,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind sample interval', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1603,6 +1631,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1663,6 +1692,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wind speed (avg)', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/weatherflow_cloud/snapshots/test_weather.ambr b/tests/components/weatherflow_cloud/snapshots/test_weather.ambr index 895333bf269..76ebba5b654 100644 --- a/tests/components/weatherflow_cloud/snapshots/test_weather.ambr +++ b/tests/components/weatherflow_cloud/snapshots/test_weather.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/webhook/test_trigger.py b/tests/components/webhook/test_trigger.py index 2f7f2900771..ce372fbebbb 100644 --- a/tests/components/webhook/test_trigger.py +++ b/tests/components/webhook/test_trigger.py @@ -12,11 +12,6 @@ from tests.common import async_capture_events from tests.typing import ClientSessionGenerator -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) async def setup_http(hass: HomeAssistant) -> None: """Set up http.""" diff --git a/tests/components/webmin/snapshots/test_sensor.ambr b/tests/components/webmin/snapshots/test_sensor.ambr index 6352c2bcf61..2ac0fdcf152 100644 --- a/tests/components/webmin/snapshots/test_sensor.ambr +++ b/tests/components/webmin/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk free inodes /', 'options': dict({ }), 'original_device_class': None, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk free inodes /media/disk1', 'options': dict({ }), 'original_device_class': None, @@ -124,6 +126,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk free inodes /media/disk2', 'options': dict({ }), 'original_device_class': None, @@ -175,6 +178,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk free space /', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -234,6 +238,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk free space /media/disk1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -293,6 +298,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk free space /media/disk2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -352,6 +358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk inode usage /', 'options': dict({ }), 'original_device_class': None, @@ -404,6 +411,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk inode usage /media/disk1', 'options': dict({ }), 'original_device_class': None, @@ -456,6 +464,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk inode usage /media/disk2', 'options': dict({ }), 'original_device_class': None, @@ -508,6 +517,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk total inodes /', 'options': dict({ }), 'original_device_class': None, @@ -559,6 +569,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk total inodes /media/disk1', 'options': dict({ }), 'original_device_class': None, @@ -610,6 +621,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk total inodes /media/disk2', 'options': dict({ }), 'original_device_class': None, @@ -661,6 +673,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk total space /', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -720,6 +733,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk total space /media/disk1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -779,6 +793,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk total space /media/disk2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -838,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk usage /', 'options': dict({ }), 'original_device_class': None, @@ -890,6 +906,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk usage /media/disk1', 'options': dict({ }), 'original_device_class': None, @@ -942,6 +959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk usage /media/disk2', 'options': dict({ }), 'original_device_class': None, @@ -994,6 +1012,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used inodes /', 'options': dict({ }), 'original_device_class': None, @@ -1045,6 +1064,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used inodes /media/disk1', 'options': dict({ }), 'original_device_class': None, @@ -1096,6 +1116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used inodes /media/disk2', 'options': dict({ }), 'original_device_class': None, @@ -1147,6 +1168,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used space /', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1206,6 +1228,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used space /media/disk1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1265,6 +1288,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disk used space /media/disk2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1324,6 +1348,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disks free space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1383,6 +1408,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disks total space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1442,6 +1468,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Disks used space', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1501,6 +1528,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load (15 min)', 'options': dict({ }), 'original_device_class': None, @@ -1552,6 +1580,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load (1 min)', 'options': dict({ }), 'original_device_class': None, @@ -1603,6 +1632,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Load (5 min)', 'options': dict({ }), 'original_device_class': None, @@ -1654,6 +1684,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory free', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1713,6 +1744,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Memory total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1772,6 +1804,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Swap free', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1831,6 +1864,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Swap total', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/websocket_api/test_commands.py b/tests/components/websocket_api/test_commands.py index 81b37a77ef4..66c528a1271 100644 --- a/tests/components/websocket_api/test_commands.py +++ b/tests/components/websocket_api/test_commands.py @@ -1,7 +1,6 @@ """Tests for WebSocket API commands.""" import asyncio -from collections.abc import Generator from copy import deepcopy import io import logging @@ -79,16 +78,6 @@ STATE_KEY_SHORT_NAMES = { STATE_KEY_LONG_NAMES = {v: k for k, v in STATE_KEY_SHORT_NAMES.items()} -@pytest.fixture(name="enable_experimental_triggers_conditions") -def enable_experimental_triggers_conditions() -> Generator[None]: - """Enable experimental triggers and conditions.""" - with patch( - "homeassistant.components.labs.async_is_preview_feature_enabled", - return_value=True, - ): - yield - - @pytest.fixture def fake_integration(hass: HomeAssistant): """Set up a mock integration with device automation support.""" @@ -3661,7 +3650,7 @@ async def test_extract_from_target_validation_error( assert "error" in msg -@pytest.mark.usefixtures("enable_experimental_triggers_conditions", "target_entities") +@pytest.mark.usefixtures("enable_labs_preview_features", "target_entities") @patch("annotatedyaml.loader.load_yaml") @pytest.mark.parametrize("automation_component", ["trigger", "condition"]) async def test_get_triggers_conditions_for_target( diff --git a/tests/components/weheat/snapshots/test_binary_sensor.ambr b/tests/components/weheat/snapshots/test_binary_sensor.ambr index 8f6f635d79e..5abd1588a25 100644 --- a/tests/components/weheat/snapshots/test_binary_sensor.ambr +++ b/tests/components/weheat/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor unit auxiliary water pump', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor unit electric heater', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor unit gas boiler heating allowed', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Indoor unit water pump', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/weheat/snapshots/test_sensor.ambr b/tests/components/weheat/snapshots/test_sensor.ambr index 8631f0ab6bf..567ca43bc3a 100644 --- a/tests/components/weheat/snapshots/test_sensor.ambr +++ b/tests/components/weheat/snapshots/test_sensor.ambr @@ -32,6 +32,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': , @@ -94,6 +95,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Central heating inlet temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -150,6 +152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Central heating pump flow', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -206,6 +209,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor speed', 'options': dict({ }), 'original_device_class': None, @@ -258,6 +262,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Compressor usage', 'options': dict({ }), 'original_device_class': None, @@ -310,6 +315,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'COP', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -364,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current room temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -420,6 +427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW bottom temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -476,6 +484,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW pump flow', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -532,6 +541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'DHW top temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -588,6 +598,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electricity used', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -644,6 +655,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Input power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -700,6 +712,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Output power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -756,6 +769,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Outside temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -812,6 +826,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Room temperature setpoint', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -868,6 +883,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy output', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -924,6 +940,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water inlet temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -980,6 +997,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water outlet temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -1036,6 +1054,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/whirlpool/snapshots/test_binary_sensor.ambr b/tests/components/whirlpool/snapshots/test_binary_sensor.ambr index 1a0445a4803..1cb396fc7f0 100644 --- a/tests/components/whirlpool/snapshots/test_binary_sensor.ambr +++ b/tests/components/whirlpool/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/whirlpool/snapshots/test_climate.ambr b/tests/components/whirlpool/snapshots/test_climate.ambr index 17b5a0cb860..07ef99d5c92 100644 --- a/tests/components/whirlpool/snapshots/test_climate.ambr +++ b/tests/components/whirlpool/snapshots/test_climate.ambr @@ -41,6 +41,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -136,6 +137,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/whirlpool/snapshots/test_sensor.ambr b/tests/components/whirlpool/snapshots/test_sensor.ambr index 976adc36025..efc374e876f 100644 --- a/tests/components/whirlpool/snapshots/test_sensor.ambr +++ b/tests/components/whirlpool/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'End time', 'options': dict({ }), 'original_device_class': , @@ -94,6 +95,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -177,6 +179,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lower oven cook mode', 'options': dict({ }), 'original_device_class': , @@ -238,6 +241,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lower oven current temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -298,6 +302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lower oven state', 'options': dict({ }), 'original_device_class': , @@ -354,6 +359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Lower oven target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -419,6 +425,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper oven cook mode', 'options': dict({ }), 'original_device_class': , @@ -480,6 +487,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper oven current temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -540,6 +548,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper oven state', 'options': dict({ }), 'original_device_class': , @@ -596,6 +605,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Upper oven target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -661,6 +671,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Cook mode', 'options': dict({ }), 'original_device_class': , @@ -722,6 +733,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -782,6 +794,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , @@ -838,6 +851,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Target temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -900,6 +914,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Detergent level', 'options': dict({ }), 'original_device_class': , @@ -956,6 +971,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'End time', 'options': dict({ }), 'original_device_class': , @@ -1034,6 +1050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'State', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/whois/snapshots/test_sensor.ambr b/tests/components/whois/snapshots/test_sensor.ambr index 30cdb9080f8..7be5153b06a 100644 --- a/tests/components/whois/snapshots/test_sensor.ambr +++ b/tests/components/whois/snapshots/test_sensor.ambr @@ -33,6 +33,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Admin', 'options': dict({ }), 'original_device_class': None, @@ -113,6 +114,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Created', 'options': dict({ }), 'original_device_class': , @@ -197,6 +199,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Days until expiration', 'options': dict({ }), 'original_device_class': None, @@ -277,6 +280,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Expires', 'options': dict({ }), 'original_device_class': , @@ -357,6 +361,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last updated', 'options': dict({ }), 'original_device_class': , @@ -436,6 +441,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Owner', 'options': dict({ }), 'original_device_class': None, @@ -515,6 +521,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Registrant', 'options': dict({ }), 'original_device_class': None, @@ -594,6 +601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Registrar', 'options': dict({ }), 'original_device_class': None, @@ -673,6 +681,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reseller', 'options': dict({ }), 'original_device_class': None, @@ -804,6 +813,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': , @@ -884,6 +894,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last updated', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/withings/snapshots/test_sensor.ambr b/tests/components/withings/snapshots/test_sensor.ambr index 21a799e7bd4..70ed76875f9 100644 --- a/tests/components/withings/snapshots/test_sensor.ambr +++ b/tests/components/withings/snapshots/test_sensor.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -82,6 +83,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active calories burnt today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -138,6 +140,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Active time today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -198,6 +201,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average heart rate', 'options': dict({ }), 'original_device_class': None, @@ -250,6 +254,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average respiratory rate', 'options': dict({ }), 'original_device_class': None, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Body temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Bone mass', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Breathing disturbances intensity', 'options': dict({ }), 'original_device_class': None, @@ -463,6 +471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Calories burnt last workout', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -517,6 +526,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Deep sleep', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -576,6 +586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Diastolic blood pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -630,6 +641,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance travelled last workout', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -685,6 +697,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Distance travelled today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -740,6 +753,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electrodermal activity feet', 'options': dict({ }), 'original_device_class': None, @@ -789,6 +803,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electrodermal activity left foot', 'options': dict({ }), 'original_device_class': None, @@ -838,6 +853,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Electrodermal activity right foot', 'options': dict({ }), 'original_device_class': None, @@ -887,6 +903,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elevation change last workout', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -942,6 +959,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Elevation change today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -999,6 +1017,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Extracellular water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1055,6 +1074,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat free mass', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1111,6 +1131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat free mass in left arm', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1167,6 +1188,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat free mass in left leg', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1223,6 +1245,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat free mass in right arm', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1279,6 +1302,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat free mass in right leg', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1335,6 +1359,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat free mass in torso', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1391,6 +1416,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat mass', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1447,6 +1473,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat mass in left arm', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1503,6 +1530,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat mass in left leg', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1559,6 +1587,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat mass in right arm', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1615,6 +1644,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat mass in right leg', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1671,6 +1701,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat mass in torso', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1727,6 +1758,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Fat ratio', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1782,6 +1814,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Heart pulse', 'options': dict({ }), 'original_device_class': None, @@ -1834,6 +1867,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Height', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1890,6 +1924,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hydration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1946,6 +1981,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intense activity today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2006,6 +2042,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intracellular water', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2060,6 +2097,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last workout duration', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2116,6 +2154,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last workout intensity', 'options': dict({ }), 'original_device_class': None, @@ -2216,6 +2255,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last workout type', 'options': dict({ }), 'original_device_class': , @@ -2318,6 +2358,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Light sleep', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2377,6 +2418,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum heart rate', 'options': dict({ }), 'original_device_class': None, @@ -2429,6 +2471,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Maximum respiratory rate', 'options': dict({ }), 'original_device_class': None, @@ -2481,6 +2524,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum heart rate', 'options': dict({ }), 'original_device_class': None, @@ -2533,6 +2577,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Minimum respiratory rate', 'options': dict({ }), 'original_device_class': None, @@ -2585,6 +2630,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Moderate activity today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2645,6 +2691,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muscle mass', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2701,6 +2748,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muscle mass in left arm', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2757,6 +2805,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muscle mass in left leg', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2813,6 +2862,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muscle mass in right arm', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2869,6 +2919,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muscle mass in right leg', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2925,6 +2976,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Muscle mass in torso', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -2979,6 +3031,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pause during last workout', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3037,6 +3090,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pulse wave velocity', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3093,6 +3147,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'REM sleep', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3152,6 +3207,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Skin temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3208,6 +3264,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep goal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3267,6 +3324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sleep score', 'options': dict({ }), 'original_device_class': None, @@ -3319,6 +3377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Snoring', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3378,6 +3437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Snoring episode count', 'options': dict({ }), 'original_device_class': None, @@ -3429,6 +3489,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Soft activity today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3489,6 +3550,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'SpO2', 'options': dict({ }), 'original_device_class': None, @@ -3541,6 +3603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Step goal', 'options': dict({ }), 'original_device_class': None, @@ -3593,6 +3656,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Steps today', 'options': dict({ }), 'original_device_class': None, @@ -3646,6 +3710,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Systolic blood pressure', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3702,6 +3767,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3758,6 +3824,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to sleep', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3817,6 +3884,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Time to wakeup', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -3876,6 +3944,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total calories burnt today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, @@ -3930,6 +3999,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Vascular age', 'options': dict({ }), 'original_device_class': None, @@ -3978,6 +4048,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Visceral fat index', 'options': dict({ }), 'original_device_class': None, @@ -4028,6 +4099,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'VO2 max', 'options': dict({ }), 'original_device_class': None, @@ -4080,6 +4152,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wakeup count', 'options': dict({ }), 'original_device_class': None, @@ -4132,6 +4205,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wakeup time', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4191,6 +4265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weight', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -4247,6 +4322,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Weight goal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/wiz/__init__.py b/tests/components/wiz/__init__.py index 037b6a1dfbd..a11a7251998 100644 --- a/tests/components/wiz/__init__.py +++ b/tests/components/wiz/__init__.py @@ -183,7 +183,7 @@ FAKE_DIMMABLE_FAN = BulbType( features=Features( color=False, color_tmp=False, - effect=True, + effect=False, brightness=True, dual_head=False, fan=True, @@ -191,11 +191,30 @@ FAKE_DIMMABLE_FAN = BulbType( fan_reverse=True, ), kelvin_range=KelvinRange(max=2700, min=2700), - fw_version="1.31.32", + fw_version="1.34.1", white_channels=1, white_to_color_ratio=20, fan_speed_range=6, ) +FAKE_DIMMABLE_FAN_2 = BulbType( + bulb_type=BulbClass.FANDIM, + name="ESP20_FANDIMS_31", + features=Features( + color=False, + color_tmp=False, + effect=False, + brightness=True, + dual_head=False, + fan=True, + fan_breeze_mode=True, + fan_reverse=True, + ), + kelvin_range=None, + fw_version="1.34.0", + white_channels=None, + white_to_color_ratio=None, + fan_speed_range=6, +) async def setup_integration(hass: HomeAssistant) -> MockConfigEntry: diff --git a/tests/components/wiz/snapshots/test_fan.ambr b/tests/components/wiz/snapshots/test_fan.ambr index 2c6b235e78b..1ab3b78513f 100644 --- a/tests/components/wiz/snapshots/test_fan.ambr +++ b/tests/components/wiz/snapshots/test_fan.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_entity[fan.mock_title-entry] +# name: test_entity[bulb_type0][fan.mock_title-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -24,6 +24,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -38,7 +39,68 @@ 'unit_of_measurement': None, }) # --- -# name: test_entity[fan.mock_title-state] +# name: test_entity[bulb_type0][fan.mock_title-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'direction': 'forward', + 'friendly_name': 'Mock Title', + 'percentage': 16, + 'percentage_step': 16.666666666666668, + 'preset_mode': None, + 'preset_modes': list([ + 'breeze', + ]), + 'supported_features': , + }), + 'context': , + 'entity_id': 'fan.mock_title', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_entity[bulb_type1][fan.mock_title-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'preset_modes': list([ + 'breeze', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'fan', + 'entity_category': None, + 'entity_id': 'fan.mock_title', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': None, + 'platform': 'wiz', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': 'abcabcabcabc', + 'unit_of_measurement': None, + }) +# --- +# name: test_entity[bulb_type1][fan.mock_title-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'direction': 'forward', diff --git a/tests/components/wiz/test_fan.py b/tests/components/wiz/test_fan.py index d15f083d431..42c022f2c45 100644 --- a/tests/components/wiz/test_fan.py +++ b/tests/components/wiz/test_fan.py @@ -3,6 +3,8 @@ from typing import Any from unittest.mock import patch +import pytest +from pywizlight import BulbType from syrupy.assertion import SnapshotAssertion from homeassistant.components.fan import ( @@ -28,7 +30,13 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from . import FAKE_DIMMABLE_FAN, FAKE_MAC, async_push_update, async_setup_integration +from . import ( + FAKE_DIMMABLE_FAN, + FAKE_DIMMABLE_FAN_2, + FAKE_MAC, + async_push_update, + async_setup_integration, +) from tests.common import snapshot_platform @@ -43,12 +51,16 @@ INITIAL_PARAMS = { } +@pytest.mark.parametrize("bulb_type", [FAKE_DIMMABLE_FAN, FAKE_DIMMABLE_FAN_2]) @patch("homeassistant.components.wiz.PLATFORMS", [Platform.FAN]) async def test_entity( - hass: HomeAssistant, snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + bulb_type: BulbType, ) -> None: """Test the fan entity.""" - entry = (await async_setup_integration(hass, bulb_type=FAKE_DIMMABLE_FAN))[1] + entry = (await async_setup_integration(hass, bulb_type=bulb_type))[1] await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id) diff --git a/tests/components/wled/snapshots/test_button.ambr b/tests/components/wled/snapshots/test_button.ambr index 7564a430db7..06fbb504a66 100644 --- a/tests/components/wled/snapshots/test_button.ambr +++ b/tests/components/wled/snapshots/test_button.ambr @@ -55,6 +55,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Restart', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/wled/snapshots/test_light.ambr b/tests/components/wled/snapshots/test_light.ambr index d9369a4c6f2..eff7cfe05e7 100644 --- a/tests/components/wled/snapshots/test_light.ambr +++ b/tests/components/wled/snapshots/test_light.ambr @@ -218,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -676,6 +677,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -937,6 +939,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Main', 'options': dict({ }), 'original_device_class': None, @@ -1184,6 +1187,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1', 'options': dict({ }), 'original_device_class': None, @@ -1634,6 +1638,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2084,6 +2089,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -2534,6 +2540,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/wled/snapshots/test_number.ambr b/tests/components/wled/snapshots/test_number.ambr index e958ba65be4..063e77edcd8 100644 --- a/tests/components/wled/snapshots/test_number.ambr +++ b/tests/components/wled/snapshots/test_number.ambr @@ -42,6 +42,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1 intensity', 'options': dict({ }), 'original_device_class': None, @@ -134,6 +135,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1 speed', 'options': dict({ }), 'original_device_class': None, @@ -209,6 +211,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Intensity', 'options': dict({ }), 'original_device_class': None, @@ -266,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1 intensity', 'options': dict({ }), 'original_device_class': None, @@ -323,6 +327,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1 speed', 'options': dict({ }), 'original_device_class': None, @@ -380,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Speed', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/wled/snapshots/test_select.ambr b/tests/components/wled/snapshots/test_select.ambr index 7287cbf411d..1880cf5ff1c 100644 --- a/tests/components/wled/snapshots/test_select.ambr +++ b/tests/components/wled/snapshots/test_select.ambr @@ -94,6 +94,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Color palette', 'options': dict({ }), 'original_device_class': None, @@ -221,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Live override', 'options': dict({ }), 'original_device_class': None, @@ -277,6 +279,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Playlist', 'options': dict({ }), 'original_device_class': None, @@ -330,6 +333,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Preset', 'options': dict({ }), 'original_device_class': None, @@ -454,6 +458,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1 color palette', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/wled/snapshots/test_sensor.ambr b/tests/components/wled/snapshots/test_sensor.ambr index c20e84d5b01..d9430bb4fa9 100644 --- a/tests/components/wled/snapshots/test_sensor.ambr +++ b/tests/components/wled/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Estimated current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free memory', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -132,6 +134,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'IP', 'options': dict({ }), 'original_device_class': None, @@ -180,6 +183,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'LED count', 'options': dict({ }), 'original_device_class': None, @@ -228,6 +232,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Max current', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -281,6 +286,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Uptime', 'options': dict({ }), 'original_device_class': , @@ -330,6 +336,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi BSSID', 'options': dict({ }), 'original_device_class': None, @@ -378,6 +385,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi channel', 'options': dict({ }), 'original_device_class': None, @@ -428,6 +436,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi RSSI', 'options': dict({ }), 'original_device_class': , @@ -481,6 +490,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Wi-Fi signal', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/wled/snapshots/test_switch.ambr b/tests/components/wled/snapshots/test_switch.ambr index 422728be5d2..f3b23452b98 100644 --- a/tests/components/wled/snapshots/test_switch.ambr +++ b/tests/components/wled/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nightlight', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Segment 1 reverse', 'options': dict({ }), 'original_device_class': None, @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync receive', 'options': dict({ }), 'original_device_class': None, @@ -215,6 +219,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync send', 'options': dict({ }), 'original_device_class': None, @@ -264,6 +269,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Nightlight', 'options': dict({ }), 'original_device_class': None, @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Reverse', 'options': dict({ }), 'original_device_class': None, @@ -362,6 +369,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync receive', 'options': dict({ }), 'original_device_class': None, @@ -411,6 +419,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Sync send', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/wled/snapshots/test_update.ambr b/tests/components/wled/snapshots/test_update.ambr index 2a61674219c..f0c04f26753 100644 --- a/tests/components/wled/snapshots/test_update.ambr +++ b/tests/components/wled/snapshots/test_update.ambr @@ -72,6 +72,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Firmware', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/wled/test_analytics.py b/tests/components/wled/test_analytics.py index 7b392c22180..fd4feb5f53a 100644 --- a/tests/components/wled/test_analytics.py +++ b/tests/components/wled/test_analytics.py @@ -1,7 +1,5 @@ """Tests for analytics platform.""" -import pytest - from homeassistant.components.analytics import async_devices_payload from homeassistant.components.wled import DOMAIN from homeassistant.core import HomeAssistant @@ -11,7 +9,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry -@pytest.mark.asyncio async def test_analytics( hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: diff --git a/tests/components/wolflink/snapshots/test_sensor.ambr b/tests/components/wolflink/snapshots/test_sensor.ambr index d66c1d2285b..0707748e851 100644 --- a/tests/components/wolflink/snapshots/test_sensor.ambr +++ b/tests/components/wolflink/snapshots/test_sensor.ambr @@ -51,6 +51,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy Parameter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -107,6 +108,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Flow Parameter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -163,6 +165,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Frequency Parameter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -219,6 +222,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Hours Parameter', 'options': dict({ }), 'original_device_class': None, @@ -272,6 +276,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'List Item Parameter', 'options': dict({ }), 'original_device_class': None, @@ -323,6 +328,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Percentage Parameter', 'options': dict({ }), 'original_device_class': None, @@ -375,6 +381,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power Parameter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -431,6 +438,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Pressure Parameter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -489,6 +497,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'RPM Parameter', 'options': dict({ }), 'original_device_class': None, @@ -542,6 +551,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Simple Parameter', 'options': dict({ }), 'original_device_class': None, @@ -593,6 +603,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Temperature Parameter', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 1, diff --git a/tests/components/wsdot/snapshots/test_sensor.ambr b/tests/components/wsdot/snapshots/test_sensor.ambr index 9b61095b00a..721f820683b 100644 --- a/tests/components/wsdot/snapshots/test_sensor.ambr +++ b/tests/components/wsdot/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Seattle-Bellevue via I-90 (EB AM)', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/xbox/fixtures/smartglass_console_status_playing.json b/tests/components/xbox/fixtures/smartglass_console_status_playing.json new file mode 100644 index 00000000000..437f2e68325 --- /dev/null +++ b/tests/components/xbox/fixtures/smartglass_console_status_playing.json @@ -0,0 +1,14 @@ +{ + "status": { + "errorCode": "OK", + "errorMessage": null + }, + "powerState": "On", + "playbackState": "Playing", + "loginState": null, + "focusAppAumid": "4DF9E0F8.Netflix_mcm4njqhnhss8!App", + "isTvConfigured": true, + "digitalAssistantRemoteControlEnabled": true, + "consoleStreamingEnabled": false, + "remoteManagementEnabled": true +} diff --git a/tests/components/xbox/snapshots/test_binary_sensor.ambr b/tests/components/xbox/snapshots/test_binary_sensor.ambr index d59492559d0..c6d292cae8c 100644 --- a/tests/components/xbox/snapshots/test_binary_sensor.ambr +++ b/tests/components/xbox/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -73,6 +74,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In game', 'options': dict({ }), 'original_device_class': None, @@ -121,6 +123,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscribed to Xbox Game Pass', 'options': dict({ }), 'original_device_class': None, @@ -169,6 +172,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -222,6 +226,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In game', 'options': dict({ }), 'original_device_class': None, @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscribed to Xbox Game Pass', 'options': dict({ }), 'original_device_class': None, @@ -318,6 +324,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -371,6 +378,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In game', 'options': dict({ }), 'original_device_class': None, @@ -419,6 +427,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Subscribed to Xbox Game Pass', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/xbox/snapshots/test_image.ambr b/tests/components/xbox/snapshots/test_image.ambr index 2a48ed47831..2980cdb5c7a 100644 --- a/tests/components/xbox/snapshots/test_image.ambr +++ b/tests/components/xbox/snapshots/test_image.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avatar', 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gamerpic', 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avatar', 'options': dict({ }), 'original_device_class': None, @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gamerpic', 'options': dict({ }), 'original_device_class': None, @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -320,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Avatar', 'options': dict({ }), 'original_device_class': None, @@ -370,6 +377,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gamerpic', 'options': dict({ }), 'original_device_class': None, @@ -420,6 +428,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/xbox/snapshots/test_media_player.ambr b/tests/components/xbox/snapshots/test_media_player.ambr index 812c71743b5..d74a3f6ec4d 100644 --- a/tests/components/xbox/snapshots/test_media_player.ambr +++ b/tests/components/xbox/snapshots/test_media_player.ambr @@ -146,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -201,6 +202,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/xbox/snapshots/test_remote.ambr b/tests/components/xbox/snapshots/test_remote.ambr index 3017649ad5a..1a1750f0bd2 100644 --- a/tests/components/xbox/snapshots/test_remote.ambr +++ b/tests/components/xbox/snapshots/test_remote.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/xbox/snapshots/test_sensor.ambr b/tests/components/xbox/snapshots/test_sensor.ambr index f23ce549002..a19fedf53fa 100644 --- a/tests/components/xbox/snapshots/test_sensor.ambr +++ b/tests/components/xbox/snapshots/test_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Follower', 'options': dict({ }), 'original_device_class': None, @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Following', 'options': dict({ }), 'original_device_class': None, @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Friends', 'options': dict({ }), 'original_device_class': None, @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gamerscore', 'options': dict({ }), 'original_device_class': None, @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In party', 'options': dict({ }), 'original_device_class': None, @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last online', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -376,6 +383,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Party join restrictions', 'options': dict({ }), 'original_device_class': , @@ -429,6 +437,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -477,6 +486,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Follower', 'options': dict({ }), 'original_device_class': None, @@ -526,6 +536,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Following', 'options': dict({ }), 'original_device_class': None, @@ -575,6 +586,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Friends', 'options': dict({ }), 'original_device_class': None, @@ -624,6 +636,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gamerscore', 'options': dict({ }), 'original_device_class': None, @@ -673,6 +686,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In party', 'options': dict({ }), 'original_device_class': None, @@ -722,6 +736,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last online', 'options': dict({ }), 'original_device_class': , @@ -771,6 +786,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -834,6 +850,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Party join restrictions', 'options': dict({ }), 'original_device_class': , @@ -887,6 +904,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -935,6 +953,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Follower', 'options': dict({ }), 'original_device_class': None, @@ -984,6 +1003,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Following', 'options': dict({ }), 'original_device_class': None, @@ -1033,6 +1053,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Friends', 'options': dict({ }), 'original_device_class': None, @@ -1082,6 +1103,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Gamerscore', 'options': dict({ }), 'original_device_class': None, @@ -1131,6 +1153,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'In party', 'options': dict({ }), 'original_device_class': None, @@ -1180,6 +1203,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Last online', 'options': dict({ }), 'original_device_class': , @@ -1229,6 +1253,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Now playing', 'options': dict({ }), 'original_device_class': None, @@ -1291,6 +1316,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Party join restrictions', 'options': dict({ }), 'original_device_class': , @@ -1344,6 +1370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Status', 'options': dict({ }), 'original_device_class': None, @@ -1394,6 +1421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space - External', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1453,6 +1481,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space - Internal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1512,6 +1541,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total space - External', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1571,6 +1601,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total space - Internal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1630,6 +1661,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Free space - Internal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1689,6 +1721,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total space - Internal', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/xbox/test_media_player.py b/tests/components/xbox/test_media_player.py index ac8db1a88f9..b9d444ed743 100644 --- a/tests/components/xbox/test_media_player.py +++ b/tests/components/xbox/test_media_player.py @@ -1,17 +1,48 @@ """Test the Xbox media_player platform.""" from collections.abc import Generator +from typing import Any from unittest.mock import patch import pytest +from pythonxbox.api.provider.smartglass.models import ( + SmartglassConsoleStatus, + VolumeDirection, +) from syrupy.assertion import SnapshotAssertion +from homeassistant.components.media_player import ( + ATTR_MEDIA_CONTENT_ID, + ATTR_MEDIA_CONTENT_TYPE, + ATTR_MEDIA_VOLUME_MUTED, + DOMAIN as MEDIA_PLAYER_DOMAIN, + SERVICE_PLAY_MEDIA, + MediaType, +) +from homeassistant.components.xbox import DOMAIN from homeassistant.config_entries import ConfigEntryState -from homeassistant.const import Platform +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_MEDIA_NEXT_TRACK, + SERVICE_MEDIA_PAUSE, + SERVICE_MEDIA_PLAY, + SERVICE_MEDIA_PREVIOUS_TRACK, + SERVICE_TURN_OFF, + SERVICE_TURN_ON, + SERVICE_VOLUME_DOWN, + SERVICE_VOLUME_MUTE, + SERVICE_VOLUME_UP, + Platform, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import ( + AsyncMock, + MockConfigEntry, + async_load_json_object_fixture, + snapshot_platform, +) from tests.typing import MagicMock, WebSocketGenerator @@ -105,3 +136,69 @@ async def test_browse_media( assert response["success"] assert response["result"] == snapshot(name="games") + + +@pytest.mark.parametrize( + ("service", "service_args", "call_method", "call_args"), + [ + (SERVICE_TURN_ON, {}, "wake_up", ()), + (SERVICE_TURN_OFF, {}, "turn_off", ()), + (SERVICE_VOLUME_MUTE, {ATTR_MEDIA_VOLUME_MUTED: False}, "unmute", ()), + (SERVICE_VOLUME_MUTE, {ATTR_MEDIA_VOLUME_MUTED: True}, "mute", ()), + (SERVICE_VOLUME_UP, {}, "volume", (VolumeDirection.Up,)), + (SERVICE_VOLUME_DOWN, {}, "volume", (VolumeDirection.Down,)), + (SERVICE_MEDIA_PLAY, {}, "play", ()), + (SERVICE_MEDIA_PAUSE, {}, "pause", ()), + (SERVICE_MEDIA_PREVIOUS_TRACK, {}, "previous", ()), + (SERVICE_MEDIA_NEXT_TRACK, {}, "next", ()), + ( + SERVICE_PLAY_MEDIA, + {ATTR_MEDIA_CONTENT_TYPE: MediaType.APP, ATTR_MEDIA_CONTENT_ID: "Home"}, + "go_home", + (), + ), + ( + SERVICE_PLAY_MEDIA, + { + ATTR_MEDIA_CONTENT_TYPE: MediaType.APP, + ATTR_MEDIA_CONTENT_ID: "327370029", + }, + "launch_app", + ("327370029",), + ), + ], +) +async def test_media_player_actions( + hass: HomeAssistant, + xbox_live_client: AsyncMock, + config_entry: MockConfigEntry, + service: str, + service_args: dict[str, Any], + call_method: str, + call_args: set[Any], +) -> None: + """Test media player actions.""" + + xbox_live_client.smartglass.get_console_status.return_value = ( + SmartglassConsoleStatus( + **await async_load_json_object_fixture( + hass, "smartglass_console_status_playing.json", DOMAIN + ) # pyright: ignore[reportArgumentType] + ) + ) + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.LOADED + + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + service, + target={ATTR_ENTITY_ID: "media_player.xone", **service_args}, + blocking=True, + ) + + getattr(xbox_live_client.smartglass, call_method).assert_called_once_with( + "HIJKLMN", *call_args + ) diff --git a/tests/components/xiaomi_miio/snapshots/test_fan.ambr b/tests/components/xiaomi_miio/snapshots/test_fan.ambr index 0a0ad2e6d31..c99665a6c65 100644 --- a/tests/components/xiaomi_miio/snapshots/test_fan.ambr +++ b/tests/components/xiaomi_miio/snapshots/test_fan.ambr @@ -25,6 +25,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -88,6 +89,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yale_smart_alarm/snapshots/test_alarm_control_panel.ambr b/tests/components/yale_smart_alarm/snapshots/test_alarm_control_panel.ambr index 2b732056991..7f577fa3c46 100644 --- a/tests/components/yale_smart_alarm/snapshots/test_alarm_control_panel.ambr +++ b/tests/components/yale_smart_alarm/snapshots/test_alarm_control_panel.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yale_smart_alarm/snapshots/test_binary_sensor.ambr b/tests/components/yale_smart_alarm/snapshots/test_binary_sensor.ambr index 9724125b989..17c6afd8aa0 100644 --- a/tests/components/yale_smart_alarm/snapshots/test_binary_sensor.ambr +++ b/tests/components/yale_smart_alarm/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -118,6 +120,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -167,6 +170,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -216,6 +220,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -265,6 +270,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Door', 'options': dict({ }), 'original_device_class': , @@ -314,6 +320,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Battery', 'options': dict({ }), 'original_device_class': , @@ -363,6 +370,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Jam', 'options': dict({ }), 'original_device_class': , @@ -412,6 +420,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power loss', 'options': dict({ }), 'original_device_class': , @@ -461,6 +470,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tamper', 'options': dict({ }), 'original_device_class': , diff --git a/tests/components/yale_smart_alarm/snapshots/test_button.ambr b/tests/components/yale_smart_alarm/snapshots/test_button.ambr index 65c36cbddad..184a2484467 100644 --- a/tests/components/yale_smart_alarm/snapshots/test_button.ambr +++ b/tests/components/yale_smart_alarm/snapshots/test_button.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Panic button', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yale_smart_alarm/snapshots/test_lock.ambr b/tests/components/yale_smart_alarm/snapshots/test_lock.ambr index ebed9ac4316..629010fbd36 100644 --- a/tests/components/yale_smart_alarm/snapshots/test_lock.ambr +++ b/tests/components/yale_smart_alarm/snapshots/test_lock.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -70,6 +71,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -120,6 +122,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -170,6 +173,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -220,6 +224,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -270,6 +275,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yale_smart_alarm/snapshots/test_select.ambr b/tests/components/yale_smart_alarm/snapshots/test_select.ambr index 04ec15b6ccb..9e4cac35833 100644 --- a/tests/components/yale_smart_alarm/snapshots/test_select.ambr +++ b/tests/components/yale_smart_alarm/snapshots/test_select.ambr @@ -26,6 +26,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -85,6 +86,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -144,6 +146,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -203,6 +206,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -262,6 +266,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, @@ -321,6 +326,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Volume', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yale_smart_alarm/snapshots/test_switch.ambr b/tests/components/yale_smart_alarm/snapshots/test_switch.ambr index 451523fd51d..a606c7e731d 100644 --- a/tests/components/yale_smart_alarm/snapshots/test_switch.ambr +++ b/tests/components/yale_smart_alarm/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Autolock', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Autolock', 'options': dict({ }), 'original_device_class': None, @@ -116,6 +118,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Autolock', 'options': dict({ }), 'original_device_class': None, @@ -164,6 +167,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Autolock', 'options': dict({ }), 'original_device_class': None, @@ -212,6 +216,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Autolock', 'options': dict({ }), 'original_device_class': None, @@ -260,6 +265,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Autolock', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yardian/snapshots/test_binary_sensor.ambr b/tests/components/yardian/snapshots/test_binary_sensor.ambr index a9373348d5a..91311b81779 100644 --- a/tests/components/yardian/snapshots/test_binary_sensor.ambr +++ b/tests/components/yardian/snapshots/test_binary_sensor.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Freeze prevent', 'options': dict({ }), 'original_device_class': , @@ -69,6 +70,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Standby', 'options': dict({ }), 'original_device_class': None, @@ -117,6 +119,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Watering running', 'options': dict({ }), 'original_device_class': , @@ -166,6 +169,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 1 enabled', 'options': dict({ }), 'original_device_class': None, @@ -214,6 +218,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 2 enabled', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/yardian/snapshots/test_sensor.ambr b/tests/components/yardian/snapshots/test_sensor.ambr index a4ba61a47e9..d28df698244 100644 --- a/tests/components/yardian/snapshots/test_sensor.ambr +++ b/tests/components/yardian/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Rain delay', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -76,6 +77,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Water hammer reduction', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -129,6 +131,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone delay', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/yardian/snapshots/test_switch.ambr b/tests/components/yardian/snapshots/test_switch.ambr index 585dcc6cfef..2cbcd8335d4 100644 --- a/tests/components/yardian/snapshots/test_switch.ambr +++ b/tests/components/yardian/snapshots/test_switch.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 1', 'options': dict({ }), 'original_device_class': None, @@ -68,6 +69,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Zone 2', 'options': dict({ }), 'original_device_class': None, diff --git a/tests/components/youless/snapshots/test_sensor.ambr b/tests/components/youless/snapshots/test_sensor.ambr index d4b7a1f4e5c..c7706b2d7e8 100644 --- a/tests/components/youless/snapshots/test_sensor.ambr +++ b/tests/components/youless/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy export tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -134,6 +136,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total gas usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -190,6 +193,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Average peak', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -246,6 +250,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -302,6 +307,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -358,6 +364,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -414,6 +421,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current power usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -470,6 +478,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -526,6 +535,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy import tariff 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -582,6 +592,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Month peak', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -638,6 +649,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -694,6 +706,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -750,6 +763,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -809,6 +823,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Tariff', 'options': dict({ }), 'original_device_class': , @@ -864,6 +879,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy import', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -920,6 +936,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 1', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -976,6 +993,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 2', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1032,6 +1050,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Voltage phase 3', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1088,6 +1107,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Current usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, @@ -1144,6 +1164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total energy', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -1200,6 +1221,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Total water usage', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, diff --git a/tests/components/zeversolar/snapshots/test_sensor.ambr b/tests/components/zeversolar/snapshots/test_sensor.ambr index 0c696dba5cb..9529217953c 100644 --- a/tests/components/zeversolar/snapshots/test_sensor.ambr +++ b/tests/components/zeversolar/snapshots/test_sensor.ambr @@ -22,6 +22,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Energy today', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 2, @@ -78,6 +79,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': 'Power', 'options': dict({ 'sensor': dict({ 'suggested_display_precision': 0, diff --git a/tests/components/zha/test_device_action.py b/tests/components/zha/test_device_action.py index 0ebee66fb9a..92cba1ed279 100644 --- a/tests/components/zha/test_device_action.py +++ b/tests/components/zha/test_device_action.py @@ -23,12 +23,6 @@ from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE from tests.common import async_get_device_automations, async_mock_service - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - SHORT_PRESS = "remote_button_short_press" COMMAND = "command" COMMAND_SINGLE = "single" diff --git a/tests/components/zha/test_device_trigger.py b/tests/components/zha/test_device_trigger.py index 42e603d3e14..0839bbfdcb9 100644 --- a/tests/components/zha/test_device_trigger.py +++ b/tests/components/zha/test_device_trigger.py @@ -23,12 +23,6 @@ from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, async_get_device_automations - -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - ON = 1 OFF = 0 SHAKEN = "device_shaken" diff --git a/tests/components/zone/test_trigger.py b/tests/components/zone/test_trigger.py index 27276c6905f..16cbb7b5418 100644 --- a/tests/components/zone/test_trigger.py +++ b/tests/components/zone/test_trigger.py @@ -11,11 +11,6 @@ from homeassistant.setup import async_setup_component from tests.common import mock_component -@pytest.fixture(autouse=True, name="stub_blueprint_populate") -def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: - """Stub copying the blueprints to the config folder.""" - - @pytest.fixture(autouse=True) async def setup_comp(hass: HomeAssistant) -> None: """Initialize components.""" diff --git a/tests/components/zwave_js/test_repairs.py b/tests/components/zwave_js/test_repairs.py index d47fd771127..cb2c5a846c7 100644 --- a/tests/components/zwave_js/test_repairs.py +++ b/tests/components/zwave_js/test_repairs.py @@ -4,8 +4,9 @@ from copy import deepcopy from unittest.mock import MagicMock, patch import pytest +from zwave_js_server.client import Client from zwave_js_server.event import Event -from zwave_js_server.model.node import Node +from zwave_js_server.model.node import Node, NodeDataType from homeassistant.components.zwave_js import DOMAIN from homeassistant.components.zwave_js.const import CONF_KEEP_OLD_DEVICES @@ -23,9 +24,12 @@ from tests.typing import ClientSessionGenerator, WebSocketGenerator async def _trigger_repair_issue( - hass: HomeAssistant, client, multisensor_6_state + hass: HomeAssistant, + client: Client, + multisensor_6_state: NodeDataType, + device_config_changed: bool = True, ) -> Node: - """Trigger repair issue.""" + """Trigger repair issue with configurable device config changed status.""" # Create a node node_state = deepcopy(multisensor_6_state) node = Node(client, node_state) @@ -40,7 +44,7 @@ async def _trigger_repair_issue( ) with patch( "zwave_js_server.model.node.Node.async_has_device_config_changed", - return_value=True, + return_value=device_config_changed, ): client.driver.controller.receive_event(event) await hass.async_block_till_done() @@ -55,9 +59,9 @@ async def test_device_config_file_changed_confirm_step( hass_client: ClientSessionGenerator, hass_ws_client: WebSocketGenerator, device_registry: dr.DeviceRegistry, - client, - multisensor_6_state, - integration, + client: Client, + multisensor_6_state: NodeDataType, + integration: MockConfigEntry, ) -> None: """Test the device_config_file_changed issue confirm step.""" node = await _trigger_repair_issue(hass, client, multisensor_6_state) @@ -116,14 +120,54 @@ async def test_device_config_file_changed_confirm_step( assert len(msg["result"]["issues"]) == 0 +async def test_device_config_file_changed_cleared( + hass: HomeAssistant, + hass_ws_client: WebSocketGenerator, + device_registry: dr.DeviceRegistry, + client: Client, + multisensor_6_state: NodeDataType, + integration: MockConfigEntry, +) -> None: + """Test the device_config_file_changed issue is cleared when no longer true.""" + node = await _trigger_repair_issue(hass, client, multisensor_6_state) + + device = device_registry.async_get_device( + identifiers={get_device_id(client.driver, node)} + ) + assert device + issue_id = f"device_config_file_changed.{device.id}" + + await async_process_repairs_platforms(hass) + ws_client = await hass_ws_client(hass) + + # Assert the issue is present + await ws_client.send_json({"id": 1, "type": "repairs/list_issues"}) + msg = await ws_client.receive_json() + assert msg["success"] + assert len(msg["result"]["issues"]) == 1 + issue = msg["result"]["issues"][0] + assert issue["issue_id"] == issue_id + + # Simulate the node becoming ready again with device config no longer changed + await _trigger_repair_issue( + hass, client, multisensor_6_state, device_config_changed=False + ) + + # Assert the issue is now cleared + await ws_client.send_json({"id": 2, "type": "repairs/list_issues"}) + msg = await ws_client.receive_json() + assert msg["success"] + assert len(msg["result"]["issues"]) == 0 + + async def test_device_config_file_changed_ignore_step( hass: HomeAssistant, hass_client: ClientSessionGenerator, hass_ws_client: WebSocketGenerator, device_registry: dr.DeviceRegistry, - client, - multisensor_6_state, - integration, + client: Client, + multisensor_6_state: NodeDataType, + integration: MockConfigEntry, ) -> None: """Test the device_config_file_changed issue ignore step.""" node = await _trigger_repair_issue(hass, client, multisensor_6_state) @@ -237,9 +281,9 @@ async def test_abort_confirm( hass_client: ClientSessionGenerator, hass_ws_client: WebSocketGenerator, device_registry: dr.DeviceRegistry, - client, - multisensor_6_state, - integration, + client: Client, + multisensor_6_state: NodeDataType, + integration: MockConfigEntry, ) -> None: """Test aborting device_config_file_changed issue in confirm step.""" node = await _trigger_repair_issue(hass, client, multisensor_6_state) diff --git a/tests/helpers/snapshots/test_entity.ambr b/tests/helpers/snapshots/test_entity.ambr index 0e2596fb755..3898e6b542f 100644 --- a/tests/helpers/snapshots/test_entity.ambr +++ b/tests/helpers/snapshots/test_entity.ambr @@ -20,6 +20,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -67,6 +68,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -114,6 +116,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, @@ -161,6 +164,7 @@ 'labels': set({ }), 'name': None, + 'object_id_base': None, 'options': dict({ }), 'original_device_class': None, diff --git a/tests/helpers/test_entity_platform.py b/tests/helpers/test_entity_platform.py index bbe7bd2870e..09a1b59c6c7 100644 --- a/tests/helpers/test_entity_platform.py +++ b/tests/helpers/test_entity_platform.py @@ -1521,6 +1521,7 @@ async def test_entity_info_added_to_entity_registry( has_entity_name=True, icon="nice:icon", name="best name", + object_id_base="best name", supported_features=5, translation_key="my_translation_key", unique_id="default", @@ -1548,6 +1549,7 @@ async def test_entity_info_added_to_entity_registry( id=ANY, modified_at=dt_util.utcnow(), name=None, + object_id_base="best name", original_device_class="mock-device-class", original_icon="nice:icon", original_name="best name", diff --git a/tests/helpers/test_entity_registry.py b/tests/helpers/test_entity_registry.py index 593e1ea9703..57774c51049 100644 --- a/tests/helpers/test_entity_registry.py +++ b/tests/helpers/test_entity_registry.py @@ -142,6 +142,7 @@ def test_get_or_create_updates_data( id=orig_entry.id, modified_at=created, name=None, + object_id_base=None, options=None, original_device_class="mock-device-class", original_icon="initial-original_icon", @@ -173,9 +174,11 @@ def test_get_or_create_updates_data( entity_category=EntityCategory.DIAGNOSTIC, has_entity_name=False, hidden_by=er.RegistryEntryHider.USER, + object_id_base="updated-name", original_device_class="new-mock-device-class", original_icon="updated-original_icon", original_name="updated-original_name", + suggested_object_id="suggested", supported_features=10, translation_key="updated-translation_key", unit_of_measurement="updated-unit_of_measurement", @@ -201,11 +204,12 @@ def test_get_or_create_updates_data( id=orig_entry.id, modified_at=modified, name=None, + object_id_base="updated-name", options=None, original_device_class="new-mock-device-class", original_icon="updated-original_icon", original_name="updated-original_name", - suggested_object_id=None, + suggested_object_id="suggested", supported_features=10, translation_key="updated-translation_key", unit_of_measurement="updated-unit_of_measurement", @@ -226,9 +230,11 @@ def test_get_or_create_updates_data( entity_category=None, has_entity_name=None, hidden_by=None, + object_id_base=None, original_device_class=None, original_icon=None, original_name=None, + suggested_object_id=None, supported_features=None, translation_key=None, unit_of_measurement=None, @@ -254,6 +260,7 @@ def test_get_or_create_updates_data( id=orig_entry.id, modified_at=modified, name=None, + object_id_base=None, options=None, original_device_class=None, original_icon=None, @@ -419,25 +426,25 @@ async def test_loading_saving_data( assert new_entry2.unit_of_measurement == "initial-unit_of_measurement" -def test_generate_entity_considers_registered_entities( +def test_get_available_entity_id_considers_registered_entities( entity_registry: er.EntityRegistry, ) -> None: """Test that we don't create entity id that are already registered.""" entry = entity_registry.async_get_or_create("light", "hue", "1234") assert entry.entity_id == "light.hue_1234" assert ( - entity_registry.async_generate_entity_id("light", "hue_1234") + entity_registry.async_get_available_entity_id("light", "hue_1234") == "light.hue_1234_2" ) -def test_generate_entity_considers_existing_entities( +def test_get_available_entity_id_considers_existing_entities( hass: HomeAssistant, entity_registry: er.EntityRegistry ) -> None: """Test that we don't create entity id that currently exists.""" hass.states.async_set("light.kitchen", "on") assert ( - entity_registry.async_generate_entity_id("light", "kitchen") + entity_registry.async_get_available_entity_id("light", "kitchen") == "light.kitchen_2" ) @@ -537,7 +544,6 @@ async def test_load_bad_data( { "aliases": [], "area_id": None, - "calculated_object_id": None, "capabilities": None, "categories": {}, "config_entry_id": None, @@ -555,6 +561,7 @@ async def test_load_bad_data( "labels": [], "modified_at": "2024-02-14T12:00:00.900075+00:00", "name": None, + "object_id_base": None, "options": None, "original_device_class": None, "original_icon": None, @@ -570,7 +577,6 @@ async def test_load_bad_data( { "aliases": [], "area_id": None, - "calculated_object_id": None, "capabilities": None, "categories": {}, "config_entry_id": None, @@ -588,6 +594,7 @@ async def test_load_bad_data( "labels": [], "modified_at": "2024-02-14T12:00:00.900075+00:00", "name": None, + "object_id_base": None, "options": None, "original_device_class": None, "original_icon": None, @@ -997,6 +1004,7 @@ async def test_migration_1_1(hass: HomeAssistant, hass_storage: dict[str, Any]) "labels": [], "modified_at": "1970-01-01T00:00:00+00:00", "name": None, + "object_id_base": None, "options": {}, "original_device_class": "best_class", "original_icon": None, @@ -1190,6 +1198,7 @@ async def test_migration_1_11( "labels": [], "modified_at": "1970-01-01T00:00:00+00:00", "name": None, + "object_id_base": None, "options": {}, "original_device_class": "best_class", "original_icon": None, @@ -1274,7 +1283,7 @@ async def test_migration_1_18( "options": {}, "original_device_class": "best_class", "original_icon": None, - "original_name": None, + "original_name": "Test Entity", "platform": "super_platform", "previous_unique_id": None, "suggested_object_id": None, @@ -1354,10 +1363,11 @@ async def test_migration_1_18( "labels": [], "modified_at": "1970-01-01T00:00:00+00:00", "name": None, + "object_id_base": "Test Entity", "options": {}, "original_device_class": "best_class", "original_icon": None, - "original_name": None, + "original_name": "Test Entity", "platform": "super_platform", "previous_unique_id": None, "suggested_object_id": None, @@ -1711,6 +1721,7 @@ async def test_update_entity_disabled_by( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -1750,6 +1761,7 @@ async def test_update_entity_disabled_by( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_1", options={"test_domain": {"key1": "value1"}}, original_device_class="device_class_1", original_icon="original_icon_1", @@ -1804,6 +1816,7 @@ async def test_update_entity_disabled_by_2( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -1845,6 +1858,7 @@ async def test_update_entity_disabled_by_2( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_1", options={"test_domain": {"key1": "value1"}}, original_device_class="device_class_1", original_icon="original_icon_1", @@ -2738,7 +2752,7 @@ async def test_entity_max_length_exceeded( ) with pytest.raises(MaxLengthExceeded) as exc_info: - entity_registry.async_generate_entity_id(long_domain_name, "sensor") + entity_registry.async_get_available_entity_id(long_domain_name, "sensor") assert exc_info.value.property_name == "domain" assert exc_info.value.max_length == 64 @@ -2752,13 +2766,19 @@ async def test_entity_max_length_exceeded( "1234567890123456789012345678901234567" ) - new_id = entity_registry.async_generate_entity_id("sensor", long_entity_id_name) + new_id = entity_registry.async_get_available_entity_id( + "sensor", long_entity_id_name + ) assert new_id == "sensor." + long_entity_id_name[: 255 - 7] hass.states.async_reserve(new_id) - new_id = entity_registry.async_generate_entity_id("sensor", long_entity_id_name) + new_id = entity_registry.async_get_available_entity_id( + "sensor", long_entity_id_name + ) assert new_id == "sensor." + long_entity_id_name[: 255 - 7 - 2] + "_2" hass.states.async_reserve(new_id) - new_id = entity_registry.async_generate_entity_id("sensor", long_entity_id_name) + new_id = entity_registry.async_get_available_entity_id( + "sensor", long_entity_id_name + ) assert new_id == "sensor." + long_entity_id_name[: 255 - 7 - 2] + "_3" @@ -3195,6 +3215,7 @@ async def test_restore_entity( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -3256,6 +3277,7 @@ async def test_restore_entity( get_initial_options=lambda: {"test_domain": {"key2": "value2"}}, has_entity_name=False, hidden_by=None, + object_id_base="original_name_2", original_device_class="device_class_2", original_icon="original_icon_2", original_name="original_name_2", @@ -3303,6 +3325,7 @@ async def test_restore_entity( labels={"label1", "label2"}, modified_at=utcnow(), name="Test Friendly Name", + object_id_base="original_name_2", options={"options_domain": {"key": "value"}, "test_domain": {"key1": "value1"}}, original_device_class="device_class_2", original_icon="original_icon_2", @@ -3461,6 +3484,7 @@ async def test_restore_migrated_entity_disabled_by( get_initial_options=lambda: {"test_domain": {"key2": "value2"}}, has_entity_name=False, hidden_by=None, + object_id_base="original_name_2", original_device_class="device_class_2", original_icon="original_icon_2", original_name="original_name_2", @@ -3497,6 +3521,7 @@ async def test_restore_migrated_entity_disabled_by( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_2", options={"test_domain": {"key1": "value1"}}, original_device_class="device_class_2", original_icon="original_icon_2", @@ -3551,6 +3576,7 @@ async def test_restore_migrated_entity_hidden_by( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -3583,6 +3609,7 @@ async def test_restore_migrated_entity_hidden_by( get_initial_options=lambda: {"test_domain": {"key2": "value2"}}, has_entity_name=False, hidden_by=entity_hidden_by, + object_id_base="original_name_2", original_device_class="device_class_2", original_icon="original_icon_2", original_name="original_name_2", @@ -3619,6 +3646,7 @@ async def test_restore_migrated_entity_hidden_by( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_2", options={"test_domain": {"key1": "value1"}}, original_device_class="device_class_2", original_icon="original_icon_2", @@ -3664,6 +3692,7 @@ async def test_restore_migrated_entity_initial_options( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -3696,6 +3725,7 @@ async def test_restore_migrated_entity_initial_options( get_initial_options=lambda: {"test_domain": {"key2": "value2"}}, has_entity_name=False, hidden_by=None, + object_id_base="original_name_2", original_device_class="device_class_2", original_icon="original_icon_2", original_name="original_name_2", @@ -3732,6 +3762,7 @@ async def test_restore_migrated_entity_initial_options( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_2", options={"test_domain": {"key2": "value2"}}, original_device_class="device_class_2", original_icon="original_icon_2", @@ -3853,6 +3884,7 @@ async def test_restore_entity_disabled_by( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -3880,6 +3912,7 @@ async def test_restore_entity_disabled_by( get_initial_options=lambda: {"test_domain": {"key2": "value2"}}, has_entity_name=False, hidden_by=None, + object_id_base="original_name_2", original_device_class="device_class_2", original_icon="original_icon_2", original_name="original_name_2", @@ -3916,6 +3949,7 @@ async def test_restore_entity_disabled_by( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_2", options={"test_domain": {"key1": "value1"}}, original_device_class="device_class_2", original_icon="original_icon_2", @@ -3979,6 +4013,7 @@ async def test_restore_entity_disabled_by_2( get_initial_options=lambda: {"test_domain": {"key1": "value1"}}, has_entity_name=True, hidden_by=er.RegistryEntryHider.INTEGRATION, + object_id_base="original_name_1", original_device_class="device_class_1", original_icon="original_icon_1", original_name="original_name_1", @@ -4006,6 +4041,7 @@ async def test_restore_entity_disabled_by_2( get_initial_options=lambda: {"test_domain": {"key2": "value2"}}, has_entity_name=False, hidden_by=None, + object_id_base="original_name_2", original_device_class="device_class_2", original_icon="original_icon_2", original_name="original_name_2", @@ -4042,6 +4078,7 @@ async def test_restore_entity_disabled_by_2( labels=set(), modified_at=utcnow(), name=None, + object_id_base="original_name_2", options={"test_domain": {"key1": "value1"}}, original_device_class="device_class_2", original_icon="original_icon_2", diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index fd8dde96d99..d58a5e03f42 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -4209,6 +4209,16 @@ async def test_referenced_labels(hass: HomeAssistant) -> None: "data_template": {"label_id": "label_in_data_template"}, }, {"action": "test.script", "data": {"without": "label_id"}}, + { + "condition": "light.is_on", + "target": {"label_id": "label_condition_target"}, + }, + { + "condition": "light.is_on", + "target": { + "label_id": ["label_condition_list_1", "label_condition_list_2"] + }, + }, { "choose": [ { @@ -4221,7 +4231,10 @@ async def test_referenced_labels(hass: HomeAssistant) -> None: ], }, { - "conditions": "{{ true == false }}", + "conditions": { + "condition": "light.is_on", + "target": {"label_id": "label_choice_2_cond"}, + }, "sequence": [ { "action": "test.script", @@ -4240,7 +4253,10 @@ async def test_referenced_labels(hass: HomeAssistant) -> None: {"event": "test_event"}, {"delay": "{{ delay_period }}"}, { - "if": [], + "if": { + "condition": "light.is_on", + "target": {"label_id": "label_if_cond"}, + }, "then": [ { "action": "test.script", @@ -4277,17 +4293,22 @@ async def test_referenced_labels(hass: HomeAssistant) -> None: ) assert script_obj.referenced_labels == { "label_choice_1_seq", + "label_choice_2_cond", "label_choice_2_seq", + "label_condition_list_1", + "label_condition_list_2", + "label_condition_target", "label_default_seq", + "label_if_cond", + "label_if_else", + "label_if_then", "label_in_data_template", "label_in_target", + "label_parallel", + "label_sequence", "label_service_list_1", "label_service_list_2", "label_service_not_list", - "label_if_then", - "label_if_else", - "label_parallel", - "label_sequence", } # Test we cache results. assert script_obj.referenced_labels is script_obj.referenced_labels @@ -4320,6 +4341,16 @@ async def test_referenced_floors(hass: HomeAssistant) -> None: "data_template": {"floor_id": "floor_in_data_template"}, }, {"action": "test.script", "data": {"without": "floor_id"}}, + { + "condition": "light.is_on", + "target": {"floor_id": "floor_condition_target"}, + }, + { + "condition": "light.is_on", + "target": { + "floor_id": ["floor_condition_list_1", "floor_condition_list_2"] + }, + }, { "choose": [ { @@ -4332,7 +4363,10 @@ async def test_referenced_floors(hass: HomeAssistant) -> None: ], }, { - "conditions": "{{ true == false }}", + "conditions": { + "condition": "light.is_on", + "target": {"floor_id": "floor_choice_2_cond"}, + }, "sequence": [ { "action": "test.script", @@ -4351,7 +4385,10 @@ async def test_referenced_floors(hass: HomeAssistant) -> None: {"event": "test_event"}, {"delay": "{{ delay_period }}"}, { - "if": [], + "if": { + "condition": "light.is_on", + "target": {"floor_id": "floor_if_cond"}, + }, "then": [ { "action": "test.script", @@ -4388,16 +4425,21 @@ async def test_referenced_floors(hass: HomeAssistant) -> None: ) assert script_obj.referenced_floors == { "floor_choice_1_seq", + "floor_choice_2_cond", "floor_choice_2_seq", + "floor_condition_list_1", + "floor_condition_list_2", + "floor_condition_target", "floor_default_seq", + "floor_if_cond", + "floor_if_else", + "floor_if_then", "floor_in_data_template", "floor_in_target", - "floor_service_list", - "floor_service_not_list", - "floor_if_then", - "floor_if_else", "floor_parallel", "floor_sequence", + "floor_service_list", + "floor_service_not_list", } # Test we cache results. assert script_obj.referenced_floors is script_obj.referenced_floors @@ -4430,6 +4472,16 @@ async def test_referenced_areas(hass: HomeAssistant) -> None: "data_template": {"area_id": "area_in_data_template"}, }, {"action": "test.script", "data": {"without": "area_id"}}, + { + "condition": "light.is_on", + "target": {"area_id": "area_condition_target"}, + }, + { + "condition": "light.is_on", + "target": { + "area_id": ["area_condition_list_1", "area_condition_list_2"] + }, + }, { "choose": [ { @@ -4442,7 +4494,10 @@ async def test_referenced_areas(hass: HomeAssistant) -> None: ], }, { - "conditions": "{{ true == false }}", + "conditions": { + "condition": "light.is_on", + "target": {"area_id": "area_choice_2_cond"}, + }, "sequence": [ { "action": "test.script", @@ -4461,7 +4516,10 @@ async def test_referenced_areas(hass: HomeAssistant) -> None: {"event": "test_event"}, {"delay": "{{ delay_period }}"}, { - "if": [], + "if": { + "condition": "light.is_on", + "target": {"area_id": "area_if_cond"}, + }, "then": [ { "action": "test.script", @@ -4498,16 +4556,21 @@ async def test_referenced_areas(hass: HomeAssistant) -> None: ) assert script_obj.referenced_areas == { "area_choice_1_seq", + "area_choice_2_cond", "area_choice_2_seq", + "area_condition_list_1", + "area_condition_list_2", + "area_condition_target", "area_default_seq", + "area_if_cond", + "area_if_else", + "area_if_then", "area_in_data_template", "area_in_target", - "area_service_list", - "area_service_not_list", - "area_if_then", - "area_if_else", "area_parallel", "area_sequence", + "area_service_list", + "area_service_not_list", # 'area_service_template', # no area extraction from template } # Test we cache results. @@ -4608,6 +4671,19 @@ async def test_referenced_entities(hass: HomeAssistant) -> None: } ], }, + { + "condition": "light.is_on", + "target": {"entity_id": "light.condition_target"}, + }, + { + "condition": "light.is_on", + "target": { + "entity_id": [ + "light.condition_list_1", + "light.condition_list_2", + ] + }, + }, { "sequence": [ { @@ -4626,6 +4702,9 @@ async def test_referenced_entities(hass: HomeAssistant) -> None: "light.choice_1_seq", "light.choice_2_cond", "light.choice_2_seq", + "light.condition_list_1", + "light.condition_list_2", + "light.condition_target", "light.default_seq", "light.direct_entity_referenced", "light.entity_in_data_template", @@ -4656,6 +4735,19 @@ async def test_referenced_devices(hass: HomeAssistant) -> None: "device_id": "condition-dev-id", "domain": "switch", }, + { + "condition": "light.is_on", + "target": {"device_id": "condition-target-dev-id"}, + }, + { + "condition": "light.is_on", + "target": { + "device_id": [ + "condition-target-list-1", + "condition-target-list-2", + ] + }, + }, { "action": "test.script", "data": {"device_id": "data-string-id"}, @@ -4753,6 +4845,9 @@ async def test_referenced_devices(hass: HomeAssistant) -> None: "choice-2-cond-dev-id", "choice-2-seq-device-target", "condition-dev-id", + "condition-target-dev-id", + "condition-target-list-1", + "condition-target-list-2", "data-string-id", "data-template-string-id", "default-device-target", diff --git a/tests/test_data_entry_flow.py b/tests/test_data_entry_flow.py index b6dc2b39c7c..55ff79e2531 100644 --- a/tests/test_data_entry_flow.py +++ b/tests/test_data_entry_flow.py @@ -1,11 +1,9 @@ """Test the flow classes.""" import asyncio -from collections.abc import Callable import dataclasses import logging -from typing import Any -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import Mock, patch import pytest import voluptuous as vol @@ -932,261 +930,6 @@ async def test_show_progress_fires_only_when_changed( ) # change (description placeholder) -@pytest.mark.parametrize( - ("task_side_effect", "flow_result"), - [ - (None, data_entry_flow.FlowResultType.CREATE_ENTRY), - (data_entry_flow.AbortFlow("fail"), data_entry_flow.FlowResultType.ABORT), - ], -) -@pytest.mark.parametrize( - ("description", "expected_description"), - [ - (None, None), - ({"title": "World"}, {"title": "World"}), - (lambda x: {"title": "World"}, {"title": "World"}), - ], -) -async def test_progress_step( - hass: HomeAssistant, - manager: MockFlowManager, - description: Callable[[data_entry_flow.FlowHandler], dict[str, Any]] - | dict[str, Any] - | None, - expected_description: dict[str, Any] | None, - task_side_effect: Exception | None, - flow_result: data_entry_flow.FlowResultType, -) -> None: - """Test progress_step decorator.""" - manager.hass = hass - events = [] - task_init_evt = asyncio.Event() - event_received_evt = asyncio.Event() - task_result = Mock() - task_result.side_effect = task_side_effect - - @callback - def capture_events(event: Event) -> None: - events.append(event) - event_received_evt.set() - - @manager.mock_reg_handler("test") - class TestFlow(data_entry_flow.FlowHandler): - VERSION = 5 - - @data_entry_flow.progress_step(description_placeholders=description) - async def async_step_init(self, user_input=None): - await task_init_evt.wait() - task_result() - - return await self.async_step_finish() - - async def async_step_finish(self, user_input=None): - return self.async_create_entry(data={}) - - hass.bus.async_listen( - data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESSED, - capture_events, - ) - - result = await manager.async_init("test") - assert result["type"] == data_entry_flow.FlowResultType.SHOW_PROGRESS - assert result["progress_action"] == "init" - description_placeholders = result["description_placeholders"] - assert description_placeholders == expected_description - assert len(manager.async_progress()) == 1 - assert len(manager.async_progress_by_handler("test")) == 1 - assert manager.async_get(result["flow_id"])["handler"] == "test" - - # Set task one done and wait for event - task_init_evt.set() - await event_received_evt.wait() - event_received_evt.clear() - assert len(events) == 1 - assert events[0].data == { - "handler": "test", - "flow_id": result["flow_id"], - "refresh": True, - } - - # Frontend refreshes the flow - result = await manager.async_configure(result["flow_id"]) - assert result["type"] == flow_result - - -@pytest.mark.parametrize( - ( - "task_init_side_effect", # side effect for initial step task - "task_next_side_effect", # side effect for next step task - "flow_result_before_init", # result before init task is done - "flow_result_after_init", # result after init task is done - "flow_result_after_next", # result after next task is done - "flow_init_events", # number of events fired after init task is done - "flow_next_events", # number of events fired after next task is done - "manager_call_after_init", # lambda to continue the flow after init task - "manager_call_after_next", # lambda to continue the flow after next task - "before_init_task_side_effect", # function called before init event - "before_next_task_side_effect", # function called before next event - ), - [ - ( # both steps show progress and complete successfully - None, - None, - data_entry_flow.FlowResultType.SHOW_PROGRESS, - data_entry_flow.FlowResultType.SHOW_PROGRESS, - data_entry_flow.FlowResultType.CREATE_ENTRY, - 1, - 2, - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda received_event, init_task_event, next_task_event: None, - lambda received_event, init_task_event, next_task_event: None, - ), - ( # first step aborts - data_entry_flow.AbortFlow("fail"), - None, - data_entry_flow.FlowResultType.SHOW_PROGRESS, - data_entry_flow.FlowResultType.ABORT, - data_entry_flow.FlowResultType.ABORT, - 1, - 1, - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda manager, result: AsyncMock(return_value=result)(), - lambda received_event, init_task_event, next_task_event: None, - lambda received_event, init_task_event, next_task_event: None, - ), - ( # first step shows progress, second step aborts - None, - data_entry_flow.AbortFlow("fail"), - data_entry_flow.FlowResultType.SHOW_PROGRESS, - data_entry_flow.FlowResultType.SHOW_PROGRESS, - data_entry_flow.FlowResultType.ABORT, - 1, - 2, - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda received_event, init_task_event, next_task_event: None, - lambda received_event, init_task_event, next_task_event: None, - ), - ( # first step task is already done, second step shows progress and completes - None, - None, - data_entry_flow.FlowResultType.SHOW_PROGRESS_DONE, - data_entry_flow.FlowResultType.SHOW_PROGRESS, - data_entry_flow.FlowResultType.CREATE_ENTRY, - 0, - 1, - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda manager, result: manager.async_configure(result["flow_id"]), - lambda received_event, - init_task_event, - next_task_event: received_event.set() or init_task_event.set(), - lambda received_event, init_task_event, next_task_event: None, - ), - ], -) -async def test_chaining_progress_steps( - hass: HomeAssistant, - manager: MockFlowManager, - task_init_side_effect: Exception | None, - task_next_side_effect: Exception | None, - flow_result_before_init: data_entry_flow.FlowResultType, - flow_result_after_init: data_entry_flow.FlowResultType, - flow_result_after_next: data_entry_flow.FlowResultType, - flow_init_events: int, - flow_next_events: int, - manager_call_after_init: Callable[ - [MockFlowManager, data_entry_flow.FlowResult], Any - ], - manager_call_after_next: Callable[ - [MockFlowManager, data_entry_flow.FlowResult], Any - ], - before_init_task_side_effect: Callable[ - [asyncio.Event, asyncio.Event, asyncio.Event], None - ], - before_next_task_side_effect: Callable[ - [asyncio.Event, asyncio.Event, asyncio.Event], None - ], -) -> None: - """Test chaining two steps with progress_step decorators.""" - manager.hass = hass - events = [] - event_received_evt = asyncio.Event() - task_init_evt = asyncio.Event() - task_next_evt = asyncio.Event() - task_init_result = Mock() - task_init_result.side_effect = task_init_side_effect - task_next_result = Mock() - task_next_result.side_effect = task_next_side_effect - - @callback - def capture_events(event: Event) -> None: - events.append(event) - event_received_evt.set() - - @manager.mock_reg_handler("test") - class TestFlow(data_entry_flow.FlowHandler): - VERSION = 5 - - def async_remove(self) -> None: - # Disable event received event to allow test to finish if flow is aborted. - event_received_evt.set() - - @data_entry_flow.progress_step() - async def async_step_init(self, user_input=None): - await task_init_evt.wait() - task_init_result() - - return await self.async_step_next() - - @data_entry_flow.progress_step() - async def async_step_next(self, user_input=None): - await task_next_evt.wait() - task_next_result() - - return await self.async_step_finish() - - async def async_step_finish(self, user_input=None): - return self.async_create_entry(data={}) - - hass.bus.async_listen( - data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESSED, - capture_events, - ) - - # Run side effect before first event is awaited - before_init_task_side_effect(event_received_evt, task_init_evt, task_next_evt) - - result = await manager.async_init("test") - assert result["type"] == flow_result_before_init - assert len(manager.async_progress()) == 1 - assert len(manager.async_progress_by_handler("test")) == 1 - assert manager.async_get(result["flow_id"])["handler"] == "test" - - # Set task init done and wait for event - task_init_evt.set() - await event_received_evt.wait() - event_received_evt.clear() - assert len(events) == flow_init_events - - # Run side effect before second event is awaited - before_next_task_side_effect(event_received_evt, task_init_evt, task_next_evt) - - # Continue the flow if needed. - result = await manager_call_after_init(manager, result) - assert result["type"] == flow_result_after_init - - # Set task next done and wait for event - task_next_evt.set() - await event_received_evt.wait() - event_received_evt.clear() - assert len(events) == flow_next_events - - # Continue the flow if needed. - result = await manager_call_after_next(manager, result) - assert result["type"] == flow_result_after_next - - async def test_abort_flow_exception_step(manager: MockFlowManager) -> None: """Test that the AbortFlow exception works in a step.""" diff --git a/tests/test_requirements.py b/tests/test_requirements.py index bb44f9df41a..0b9dc1c8a79 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -661,11 +661,12 @@ async def test_discovery_requirements_dhcp(hass: HomeAssistant) -> None: @pytest.mark.parametrize( - ("requirement", "is_built_in", "deprecation_info"), + ("requirement", "is_built_in", "deprecation_prefix", "deprecation_info"), [ ( "hello", True, + "Detected that integration", "which is deprecated for testing. This will stop working in Home Assistant" " 2020.12, please create a bug report at https://github.com/home-assistant/" "core/issues?q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+test_component%22", @@ -673,6 +674,7 @@ async def test_discovery_requirements_dhcp(hass: HomeAssistant) -> None: ( "hello>=1.0.0", False, + "Detected that custom integration", "which is deprecated for testing. This will stop working in Home Assistant" " 2020.12, please create a bug report at https://github.com/home-assistant/" "core/issues?q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+test_component%22", @@ -680,6 +682,7 @@ async def test_discovery_requirements_dhcp(hass: HomeAssistant) -> None: ( "pyserial-asyncio", False, + "Detected that custom integration", "which should be replaced by pyserial-asyncio-fast. This will stop" " working in Home Assistant 2026.7, please create a bug report at " "https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue+" @@ -688,6 +691,7 @@ async def test_discovery_requirements_dhcp(hass: HomeAssistant) -> None: ( "pyserial-asyncio>=0.6", True, + "Detected that integration", "which should be replaced by pyserial-asyncio-fast. This will stop" " working in Home Assistant 2026.7, please create a bug report at " "https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue+" @@ -699,6 +703,7 @@ async def test_install_deprecated_package( hass: HomeAssistant, requirement: str, is_built_in: bool, + deprecation_prefix: str, deprecation_info: str, caplog: pytest.LogCaptureFixture, ) -> None: @@ -710,10 +715,16 @@ async def test_install_deprecated_package( patch("homeassistant.util.package.install_package", return_value=True), ): await async_process_requirements( - hass, "test_component", [requirement], is_built_in + hass, + "test_component", + [ + requirement, + "git+https://github.com/user/project.git@1.2.3", + ], + is_built_in, ) assert ( - f"Detected that {'' if is_built_in else 'custom '}integration " - f"'test_component' has requirement '{requirement}' {deprecation_info}" + f"{deprecation_prefix} 'test_component'" + f" has requirement '{requirement}' {deprecation_info}" ) in caplog.text diff --git a/tests/util/test_unit_conversion.py b/tests/util/test_unit_conversion.py index 7351ef60d3a..82a275e1d73 100644 --- a/tests/util/test_unit_conversion.py +++ b/tests/util/test_unit_conversion.py @@ -56,11 +56,14 @@ from homeassistant.util.unit_conversion import ( InformationConverter, MassConverter, MassVolumeConcentrationConverter, + NitrogenDioxideConcentrationConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, ReactivePowerConverter, SpeedConverter, + SulphurDioxideConcentrationConverter, TemperatureConverter, TemperatureDeltaConverter, UnitlessRatioConverter, @@ -91,6 +94,7 @@ _ALL_CONVERTERS: dict[type[BaseUnitConverter], list[str | None]] = { InformationConverter, MassConverter, ApparentPowerConverter, + OzoneConcentrationConverter, PowerConverter, PressureConverter, ReactiveEnergyConverter, @@ -102,6 +106,8 @@ _ALL_CONVERTERS: dict[type[BaseUnitConverter], list[str | None]] = { EnergyDistanceConverter, VolumeConverter, VolumeFlowRateConverter, + NitrogenDioxideConcentrationConverter, + SulphurDioxideConcentrationConverter, ) } @@ -158,6 +164,16 @@ _GET_UNIT_RATIO: dict[type[BaseUnitConverter], tuple[str | None, str | None, flo CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, 1000, ), + NitrogenDioxideConcentrationConverter: ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION, + 1.912503, + ), + OzoneConcentrationConverter: ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION, + 1.995417, + ), PowerConverter: (UnitOfPower.WATT, UnitOfPower.KILO_WATT, 1000), PressureConverter: (UnitOfPressure.HPA, UnitOfPressure.INHG, 33.86389), ReactiveEnergyConverter: ( @@ -175,6 +191,11 @@ _GET_UNIT_RATIO: dict[type[BaseUnitConverter], tuple[str | None, str | None, flo UnitOfSpeed.MILES_PER_HOUR, 1.609343, ), + SulphurDioxideConcentrationConverter: ( + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_BILLION, + 2.6633, + ), TemperatureConverter: ( UnitOfTemperature.CELSIUS, UnitOfTemperature.FAHRENHEIT, @@ -295,7 +316,32 @@ _CONVERTED_VALUE: dict[ ), ], CarbonMonoxideConcentrationConverter: [ + # PPB to other units + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 0.001, + CONCENTRATION_PARTS_PER_MILLION, + ), + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 1.16441, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 0.00116441, + CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, + ), # PPM to other units + ( + 1, + CONCENTRATION_PARTS_PER_MILLION, + 1000, + CONCENTRATION_PARTS_PER_BILLION, + ), ( 1, CONCENTRATION_PARTS_PER_MILLION, @@ -308,24 +354,17 @@ _CONVERTED_VALUE: dict[ 1164.41, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ), - # MILLIGRAMS_PER_CUBIC_METER to other units - ( - 120, - CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, - 103.05655, - CONCENTRATION_PARTS_PER_MILLION, - ), - ( - 120, - CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, - 120000, - CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - ), # MICROGRAMS_PER_CUBIC_METER to other units ( 120000, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - 103.05655, + 103056.5, + CONCENTRATION_PARTS_PER_BILLION, + ), + ( + 120000, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + 103.0565, CONCENTRATION_PARTS_PER_MILLION, ), ( @@ -334,6 +373,39 @@ _CONVERTED_VALUE: dict[ 120, CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, ), + # MILLIGRAMS_PER_CUBIC_METER to other units + ( + 120, + CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, + 103056.5, + CONCENTRATION_PARTS_PER_BILLION, + ), + ( + 120, + CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, + 103.0565, + CONCENTRATION_PARTS_PER_MILLION, + ), + ( + 120, + CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, + 120000, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + ], + NitrogenDioxideConcentrationConverter: [ + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 1.912503, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + ( + 120, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + 62.744976, + CONCENTRATION_PARTS_PER_BILLION, + ), ], ConductivityConverter: [ ( @@ -670,6 +742,20 @@ _CONVERTED_VALUE: dict[ (1, UnitOfMass.STONES, 14, UnitOfMass.POUNDS), (1, UnitOfMass.STONES, 224, UnitOfMass.OUNCES), ], + OzoneConcentrationConverter: [ + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 1.995417, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + ( + 120, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + 60.1378, + CONCENTRATION_PARTS_PER_BILLION, + ), + ], PowerConverter: [ (10, UnitOfPower.KILO_WATT, 10000, UnitOfPower.WATT), (10, UnitOfPower.MEGA_WATT, 10e6, UnitOfPower.WATT), @@ -846,6 +932,20 @@ _CONVERTED_VALUE: dict[ # float(round(((20.7 m/s / 0.836) ** 2) ** (1 / 3))) = 8.0Bft (20.7, UnitOfSpeed.METERS_PER_SECOND, 8.0, UnitOfSpeed.BEAUFORT), ], + SulphurDioxideConcentrationConverter: [ + ( + 1, + CONCENTRATION_PARTS_PER_BILLION, + 2.6633, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + ( + 120, + CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + 45.056879, + CONCENTRATION_PARTS_PER_BILLION, + ), + ], TemperatureConverter: [ (100, UnitOfTemperature.CELSIUS, 212, UnitOfTemperature.FAHRENHEIT), (100, UnitOfTemperature.CELSIUS, 373.15, UnitOfTemperature.KELVIN),